@@ -2082,71 +2082,79 @@ void AttributeChecker::visitRethrowsAttr(RethrowsAttr *attr) {
20822082 attr->setInvalid ();
20832083}
20842084
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+ }
20902101
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 ;
20932117
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 ;
20982120 }
2099- });
2100- }
2121+ }
21012122
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 ;
21102125
21112126 if (!attr->isFullSpecialization ())
21122127 return ;
21132128
2114- if (constrainedGenericParams. size () == genericSig-> getGenericParams (). size ())
2129+ if (specializedSig-> areAllParamsConcrete ())
21152130 return ;
21162131
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;
21212133
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);
21332140 }
21342141 }
2135- }
21362142
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 ();
21482145
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+ }
21502158}
21512159
21522160// / Type check that a set of requirements provided by @_specialize.
@@ -2183,93 +2191,9 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
21832191 // First, add the old generic signature.
21842192 Builder.addGenericSignature (genericSig);
21852193
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-
21912194 // Go over the set of requirements, adding them to the builder.
21922195 WhereClauseOwner (FD, attr).visitRequirements (TypeResolutionStage::Interface,
21932196 [&](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-
22732197 // Add the requirement to the generic signature builder.
22742198 using FloatingRequirementSource =
22752199 GenericSignatureBuilder::FloatingRequirementSource;
@@ -2279,12 +2203,13 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
22792203 return false ;
22802204 });
22812205
2282- // Check the validity of provided requirements.
2283- checkSpecializeAttrRequirements (attr, FD, constrainedGenericParams, Ctx);
2284-
22852206 // Check the result.
22862207 auto specializedSig = std::move (Builder).computeGenericSignature (
22872208 /* allowConcreteGenericParams=*/ true );
2209+
2210+ // Check the validity of provided requirements.
2211+ checkSpecializeAttrRequirements (attr, genericSig, specializedSig, Ctx);
2212+
22882213 attr->setSpecializedSignature (specializedSig);
22892214
22902215 // Check the target function if there is one.
0 commit comments