Skip to content

Commit 69cf113

Browse files
authored
Merge pull request swiftlang#36480 from slavapestov/specialize-attr-cleanup
Sema: Clean up @_specialize diagnostics
2 parents 26831c6 + 568d99f commit 69cf113

File tree

4 files changed

+124
-176
lines changed

4 files changed

+124
-176
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5403,21 +5403,17 @@ ERROR(specialize_missing_where_clause,none,
54035403
ERROR(specialize_empty_where_clause,none,
54045404
"empty 'where' clause in '_specialize' attribute", ())
54055405
ERROR(specialize_attr_non_concrete_same_type_req,none,
5406-
"Only concrete type same-type requirements are supported by '_specialize' attribute", ())
5406+
"only concrete type same-type requirements are supported by '_specialize' attribute", ())
54075407
ERROR(specialize_attr_only_generic_param_req,none,
5408-
"Only requirements on generic parameters are supported by '_specialize' attribute", ())
5409-
ERROR(specialize_attr_only_one_concrete_same_type_req,none,
5410-
"Only one concrete type should be used in the same-type requirement in '_specialize' attribute", ())
5411-
ERROR(specialize_attr_non_protocol_type_constraint_req,none,
5412-
"Only conformances to protocol types are supported by '_specialize' attribute", ())
5408+
"only requirements on generic parameters are supported by '_specialize' attribute", ())
54135409
ERROR(specialize_attr_type_parameter_count_mismatch,none,
5414-
"%select{too many|too few}2 type parameters are specified "
5415-
"in '_specialize' attribute (got %1, but expected %0)",
5416-
(unsigned, unsigned, bool))
5417-
ERROR(specialize_attr_missing_constraint,none,
5418-
"Missing constraint for %0 in '_specialize' attribute", (DeclName))
5410+
"too few generic parameters are specified "
5411+
"in '_specialize' attribute (got %0, but expected %1)",
5412+
(unsigned, unsigned))
5413+
NOTE(specialize_attr_missing_constraint,none,
5414+
"missing constraint for %0 in '_specialize' attribute", (DeclName))
54195415
ERROR(specialize_attr_unsupported_kind_of_req,none,
5420-
"Only same-type and layout requirements are supported by '_specialize' attribute", ())
5416+
"only same-type and layout requirements are supported by '_specialize' attribute", ())
54215417
ERROR(specialize_target_function_not_found, none,
54225418
"target function %0 could not be found", (DeclNameRef))
54235419
ERROR(specialize_target_function_of_type_not_found, none,

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5103,7 +5103,9 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirement(
51035103
return addSameTypeRequirement(paOrT1, paOrT2, source, unresolvedHandling,
51045104
[&](Type type1, Type type2) {
51055105
Impl->HadAnyError = true;
5106-
if (source.getLoc().isValid()) {
5106+
if (source.getLoc().isValid() &&
5107+
!type1->hasError() &&
5108+
!type2->hasError()) {
51075109
Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
51085110
type1, type2);
51095111
}
@@ -5284,7 +5286,9 @@ GenericSignatureBuilder::addRequirement(const Requirement &req,
52845286
UnresolvedHandlingKind::GenerateConstraints,
52855287
[&](Type type1, Type type2) {
52865288
Impl->HadAnyError = true;
5287-
if (source.getLoc().isValid()) {
5289+
if (source.getLoc().isValid() &&
5290+
!type1->hasError() &&
5291+
!type2->hasError()) {
52885292
Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
52895293
type1, type2);
52905294
}

lib/Sema/TypeCheckAttr.cpp

Lines changed: 62 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)