@@ -2082,71 +2082,79 @@ void AttributeChecker::visitRethrowsAttr(RethrowsAttr *attr) {
2082
2082
attr->setInvalid ();
2083
2083
}
2084
2084
2085
- // / Collect all used generic parameter types from a given type.
2086
- static void collectUsedGenericParameters (
2087
- Type Ty, SmallPtrSetImpl<TypeBase *> &ConstrainedGenericParams) {
2088
- if (!Ty)
2089
- return ;
2085
+ // / Ensure that the requirements provided by the @_specialize attribute
2086
+ // / can be supported by the SIL EagerSpecializer pass.
2087
+ static void checkSpecializeAttrRequirements (SpecializeAttr *attr,
2088
+ GenericSignature originalSig,
2089
+ GenericSignature specializedSig,
2090
+ ASTContext &ctx) {
2091
+ bool hadError = false ;
2092
+
2093
+ auto specializedReqs = specializedSig->requirementsNotSatisfiedBy (originalSig);
2094
+ for (auto specializedReq : specializedReqs) {
2095
+ if (!specializedReq.getFirstType ()->is <GenericTypeParamType>()) {
2096
+ ctx.Diags .diagnose (attr->getLocation (),
2097
+ diag::specialize_attr_only_generic_param_req);
2098
+ hadError = true ;
2099
+ continue ;
2100
+ }
2090
2101
2091
- if (!Ty->hasTypeParameter ())
2092
- return ;
2102
+ switch (specializedReq.getKind ()) {
2103
+ case RequirementKind::Conformance:
2104
+ case RequirementKind::Superclass:
2105
+ ctx.Diags .diagnose (attr->getLocation (),
2106
+ diag::specialize_attr_unsupported_kind_of_req);
2107
+ hadError = true ;
2108
+ break ;
2109
+
2110
+ case RequirementKind::SameType:
2111
+ if (specializedReq.getSecondType ()->isTypeParameter ()) {
2112
+ ctx.Diags .diagnose (attr->getLocation (),
2113
+ diag::specialize_attr_non_concrete_same_type_req);
2114
+ hadError = true ;
2115
+ }
2116
+ break ;
2093
2117
2094
- // Add used generic parameters/archetypes.
2095
- Ty.visit ([&](Type Ty) {
2096
- if (auto GP = dyn_cast<GenericTypeParamType>(Ty->getCanonicalType ())) {
2097
- ConstrainedGenericParams.insert (GP);
2118
+ case RequirementKind::Layout:
2119
+ break ;
2098
2120
}
2099
- });
2100
- }
2121
+ }
2101
2122
2102
- // / Perform some sanity checks for the requirements provided by
2103
- // / the @_specialize attribute.
2104
- static void checkSpecializeAttrRequirements (
2105
- SpecializeAttr *attr,
2106
- AbstractFunctionDecl *FD,
2107
- const SmallPtrSet<TypeBase *, 4 > &constrainedGenericParams,
2108
- ASTContext &ctx) {
2109
- auto genericSig = FD->getGenericSignature ();
2123
+ if (hadError)
2124
+ return ;
2110
2125
2111
2126
if (!attr->isFullSpecialization ())
2112
2127
return ;
2113
2128
2114
- if (constrainedGenericParams. size () == genericSig-> getGenericParams (). size ())
2129
+ if (specializedSig-> areAllParamsConcrete ())
2115
2130
return ;
2116
2131
2117
- ctx.Diags .diagnose (
2118
- attr->getLocation (), diag::specialize_attr_type_parameter_count_mismatch,
2119
- genericSig->getGenericParams ().size (), constrainedGenericParams.size (),
2120
- constrainedGenericParams.size () < genericSig->getGenericParams ().size ());
2132
+ SmallVector<GenericTypeParamType *, 2 > unspecializedParams;
2121
2133
2122
- if (constrainedGenericParams.size () < genericSig->getGenericParams ().size ()) {
2123
- // Figure out which archetypes are not constrained.
2124
- for (auto gp : genericSig->getGenericParams ()) {
2125
- if (constrainedGenericParams.count (gp->getCanonicalType ().getPointer ()))
2126
- continue ;
2127
- auto gpDecl = gp->getDecl ();
2128
- if (gpDecl) {
2129
- ctx.Diags .diagnose (attr->getLocation (),
2130
- diag::specialize_attr_missing_constraint,
2131
- gpDecl->getName ());
2132
- }
2134
+ for (auto *paramTy : specializedSig->getGenericParams ()) {
2135
+ auto canTy = paramTy->getCanonicalType ();
2136
+ if (specializedSig->isCanonicalTypeInContext (canTy) &&
2137
+ (!specializedSig->getLayoutConstraint (canTy) ||
2138
+ originalSig->getLayoutConstraint (canTy))) {
2139
+ unspecializedParams.push_back (paramTy);
2133
2140
}
2134
2141
}
2135
- }
2136
2142
2137
- // / Require that the given type either not involve type parameters or be
2138
- // / a type parameter.
2139
- static bool diagnoseIndirectGenericTypeParam (SourceLoc loc, Type type,
2140
- TypeRepr *typeRepr) {
2141
- if (type->hasTypeParameter () && !type->is <GenericTypeParamType>()) {
2142
- type->getASTContext ().Diags .diagnose (
2143
- loc,
2144
- diag::specialize_attr_only_generic_param_req)
2145
- .highlight (typeRepr->getSourceRange ());
2146
- return true ;
2147
- }
2143
+ unsigned expectedCount = specializedSig->getGenericParams ().size ();
2144
+ unsigned gotCount = expectedCount - unspecializedParams.size ();
2148
2145
2149
- return false ;
2146
+ if (expectedCount == gotCount)
2147
+ return ;
2148
+
2149
+ ctx.Diags .diagnose (
2150
+ attr->getLocation (), diag::specialize_attr_type_parameter_count_mismatch,
2151
+ gotCount, expectedCount);
2152
+
2153
+ for (auto paramTy : unspecializedParams) {
2154
+ ctx.Diags .diagnose (attr->getLocation (),
2155
+ diag::specialize_attr_missing_constraint,
2156
+ paramTy->getName ());
2157
+ }
2150
2158
}
2151
2159
2152
2160
// / Type check that a set of requirements provided by @_specialize.
@@ -2183,93 +2191,9 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
2183
2191
// First, add the old generic signature.
2184
2192
Builder.addGenericSignature (genericSig);
2185
2193
2186
- // Set of generic parameters being constrained. It is used to
2187
- // determine if a full specialization misses requirements for
2188
- // some of the generic parameters.
2189
- SmallPtrSet<TypeBase *, 4 > constrainedGenericParams;
2190
-
2191
2194
// Go over the set of requirements, adding them to the builder.
2192
2195
WhereClauseOwner (FD, attr).visitRequirements (TypeResolutionStage::Interface,
2193
2196
[&](const Requirement &req, RequirementRepr *reqRepr) {
2194
- // Collect all of the generic parameters used by these types.
2195
- switch (req.getKind ()) {
2196
- case RequirementKind::Conformance:
2197
- case RequirementKind::SameType:
2198
- case RequirementKind::Superclass:
2199
- collectUsedGenericParameters (req.getSecondType (),
2200
- constrainedGenericParams);
2201
- LLVM_FALLTHROUGH;
2202
-
2203
- case RequirementKind::Layout:
2204
- collectUsedGenericParameters (req.getFirstType (),
2205
- constrainedGenericParams);
2206
- break ;
2207
- }
2208
-
2209
- // Check additional constraints.
2210
- // FIXME: These likely aren't fundamental limitations.
2211
- switch (req.getKind ()) {
2212
- case RequirementKind::SameType: {
2213
- bool firstHasTypeParameter = req.getFirstType ()->hasTypeParameter ();
2214
- bool secondHasTypeParameter = req.getSecondType ()->hasTypeParameter ();
2215
-
2216
- // Exactly one type can have a type parameter.
2217
- if (firstHasTypeParameter == secondHasTypeParameter) {
2218
- diagnose (attr->getLocation (),
2219
- firstHasTypeParameter
2220
- ? diag::specialize_attr_non_concrete_same_type_req
2221
- : diag::specialize_attr_only_one_concrete_same_type_req)
2222
- .highlight (reqRepr->getSourceRange ());
2223
- return false ;
2224
- }
2225
-
2226
- // We either need a fully-concrete type or a generic type parameter.
2227
- if (diagnoseIndirectGenericTypeParam (attr->getLocation (),
2228
- req.getFirstType (),
2229
- reqRepr->getFirstTypeRepr ()) ||
2230
- diagnoseIndirectGenericTypeParam (attr->getLocation (),
2231
- req.getSecondType (),
2232
- reqRepr->getSecondTypeRepr ())) {
2233
- return false ;
2234
- }
2235
- break ;
2236
- }
2237
-
2238
- case RequirementKind::Superclass:
2239
- diagnose (attr->getLocation (),
2240
- diag::specialize_attr_non_protocol_type_constraint_req)
2241
- .highlight (reqRepr->getSourceRange ());
2242
- return false ;
2243
-
2244
- case RequirementKind::Conformance:
2245
- if (diagnoseIndirectGenericTypeParam (attr->getLocation (),
2246
- req.getFirstType (),
2247
- reqRepr->getSubjectRepr ())) {
2248
- return false ;
2249
- }
2250
-
2251
- if (!req.getSecondType ()->is <ProtocolType>()) {
2252
- diagnose (attr->getLocation (),
2253
- diag::specialize_attr_non_protocol_type_constraint_req)
2254
- .highlight (reqRepr->getSourceRange ());
2255
- return false ;
2256
- }
2257
-
2258
- diagnose (attr->getLocation (),
2259
- diag::specialize_attr_unsupported_kind_of_req)
2260
- .highlight (reqRepr->getSourceRange ());
2261
-
2262
- return false ;
2263
-
2264
- case RequirementKind::Layout:
2265
- if (diagnoseIndirectGenericTypeParam (attr->getLocation (),
2266
- req.getFirstType (),
2267
- reqRepr->getSubjectRepr ())) {
2268
- return false ;
2269
- }
2270
- break ;
2271
- }
2272
-
2273
2197
// Add the requirement to the generic signature builder.
2274
2198
using FloatingRequirementSource =
2275
2199
GenericSignatureBuilder::FloatingRequirementSource;
@@ -2279,12 +2203,13 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
2279
2203
return false ;
2280
2204
});
2281
2205
2282
- // Check the validity of provided requirements.
2283
- checkSpecializeAttrRequirements (attr, FD, constrainedGenericParams, Ctx);
2284
-
2285
2206
// Check the result.
2286
2207
auto specializedSig = std::move (Builder).computeGenericSignature (
2287
2208
/* allowConcreteGenericParams=*/ true );
2209
+
2210
+ // Check the validity of provided requirements.
2211
+ checkSpecializeAttrRequirements (attr, genericSig, specializedSig, Ctx);
2212
+
2288
2213
attr->setSpecializedSignature (specializedSig);
2289
2214
2290
2215
// Check the target function if there is one.
0 commit comments