Skip to content

Commit 6f4f9f8

Browse files
authored
Merge pull request swiftlang#36411 from slavapestov/fix-gsb-verification
GSB: Move signature verification from CanGenericSignature::getCanonical() to computeGenericSignature()
2 parents 86fa47b + 91ebe44 commit 6f4f9f8

File tree

6 files changed

+197
-178
lines changed

6 files changed

+197
-178
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ class CanGenericSignature : public GenericSignature {
175175
/// requirements, first canonicalizing the types.
176176
static CanGenericSignature
177177
getCanonical(TypeArrayView<GenericTypeParamType> params,
178-
ArrayRef<Requirement> requirements, bool skipValidation = false);
178+
ArrayRef<Requirement> requirements);
179179

180180
public:
181181
CanGenericSignature(std::nullptr_t) : GenericSignature(nullptr) {}
@@ -342,6 +342,8 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
342342
///
343343
/// The type parameters must be known to not be concrete within the context.
344344
bool areSameTypeParameterInContext(Type type1, Type type2) const;
345+
bool areSameTypeParameterInContext(Type type1, Type type2,
346+
GenericSignatureBuilder &builder) const;
345347

346348
/// Determine if \c sig can prove \c requirement, meaning that it can deduce
347349
/// T: Foo or T == U (etc.) with the information it knows. This includes
@@ -360,12 +362,10 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
360362
/// Return the canonical version of the given type under this generic
361363
/// signature.
362364
CanType getCanonicalTypeInContext(Type type) const;
363-
bool isCanonicalTypeInContext(Type type) const;
364-
365-
/// Return the canonical version of the given type under this generic
366-
/// signature.
367365
CanType getCanonicalTypeInContext(Type type,
368366
GenericSignatureBuilder &builder) const;
367+
368+
bool isCanonicalTypeInContext(Type type) const;
369369
bool isCanonicalTypeInContext(Type type,
370370
GenericSignatureBuilder &builder) const;
371371

lib/AST/GenericSignature.cpp

Lines changed: 14 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -176,23 +176,9 @@ bool GenericSignatureImpl::isCanonical() const {
176176
return getCanonicalSignature().getPointer() == this;
177177
}
178178

179-
#ifndef NDEBUG
180-
/// Determine the canonical ordering of requirements.
181-
static unsigned getRequirementKindOrder(RequirementKind kind) {
182-
switch (kind) {
183-
case RequirementKind::Conformance: return 2;
184-
case RequirementKind::Superclass: return 0;
185-
case RequirementKind::SameType: return 3;
186-
case RequirementKind::Layout: return 1;
187-
}
188-
llvm_unreachable("unhandled kind");
189-
}
190-
#endif
191-
192179
CanGenericSignature
193180
CanGenericSignature::getCanonical(TypeArrayView<GenericTypeParamType> params,
194-
ArrayRef<Requirement> requirements,
195-
bool skipValidation) {
181+
ArrayRef<Requirement> requirements) {
196182
// Canonicalize the parameters and requirements.
197183
SmallVector<GenericTypeParamType*, 8> canonicalParams;
198184
canonicalParams.reserve(params.size());
@@ -205,116 +191,9 @@ CanGenericSignature::getCanonical(TypeArrayView<GenericTypeParamType> params,
205191
for (auto &reqt : requirements)
206192
canonicalRequirements.push_back(reqt.getCanonical());
207193

208-
(void)skipValidation;
209194
auto canSig = get(canonicalParams, canonicalRequirements,
210195
/*isKnownCanonical=*/true);
211196

212-
#ifndef NDEBUG
213-
if (skipValidation)
214-
return CanGenericSignature(canSig);
215-
216-
PrettyStackTraceGenericSignature debugStack("canonicalizing", canSig);
217-
218-
// Check that the signature is canonical.
219-
for (unsigned idx : indices(canonicalRequirements)) {
220-
debugStack.setRequirement(idx);
221-
222-
const auto &reqt = canonicalRequirements[idx];
223-
224-
// Left-hand side must be canonical in its context.
225-
// Check canonicalization of requirement itself.
226-
switch (reqt.getKind()) {
227-
case RequirementKind::Superclass:
228-
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType()) &&
229-
"Left-hand side is not canonical");
230-
assert(canSig->isCanonicalTypeInContext(reqt.getSecondType()) &&
231-
"Superclass type isn't canonical in its own context");
232-
break;
233-
234-
case RequirementKind::Layout:
235-
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType()) &&
236-
"Left-hand side is not canonical");
237-
break;
238-
239-
case RequirementKind::SameType: {
240-
auto isCanonicalAnchor = [&](Type type) {
241-
if (auto *dmt = type->getAs<DependentMemberType>())
242-
return canSig->isCanonicalTypeInContext(dmt->getBase());
243-
return type->is<GenericTypeParamType>();
244-
};
245-
246-
auto firstType = reqt.getFirstType();
247-
auto secondType = reqt.getSecondType();
248-
assert(isCanonicalAnchor(firstType));
249-
250-
if (reqt.getSecondType()->isTypeParameter()) {
251-
assert(isCanonicalAnchor(secondType));
252-
assert(compareDependentTypes(firstType, secondType) < 0 &&
253-
"Out-of-order type parameters in same-type constraint");
254-
} else {
255-
assert(canSig->isCanonicalTypeInContext(secondType) &&
256-
"Concrete same-type isn't canonical in its own context");
257-
}
258-
break;
259-
}
260-
261-
case RequirementKind::Conformance:
262-
assert(reqt.getFirstType()->isTypeParameter() &&
263-
"Left-hand side must be a type parameter");
264-
assert(isa<ProtocolType>(reqt.getSecondType().getPointer()) &&
265-
"Right-hand side of conformance isn't a protocol type");
266-
break;
267-
}
268-
269-
// From here on, we're only interested in requirements beyond the first.
270-
if (idx == 0) continue;
271-
272-
// Make sure that the left-hand sides are in nondecreasing order.
273-
const auto &prevReqt = canonicalRequirements[idx-1];
274-
int compareLHS =
275-
compareDependentTypes(prevReqt.getFirstType(), reqt.getFirstType());
276-
assert(compareLHS <= 0 && "Out-of-order left-hand sides");
277-
278-
// If we have two same-type requirements where the left-hand sides differ
279-
// but fall into the same equivalence class, we can check the form.
280-
if (compareLHS < 0 && reqt.getKind() == RequirementKind::SameType &&
281-
prevReqt.getKind() == RequirementKind::SameType &&
282-
canSig->areSameTypeParameterInContext(prevReqt.getFirstType(),
283-
reqt.getFirstType())) {
284-
// If it's a it's a type parameter, make sure the equivalence class is
285-
// wired together sanely.
286-
if (prevReqt.getSecondType()->isTypeParameter()) {
287-
assert(prevReqt.getSecondType()->isEqual(reqt.getFirstType()) &&
288-
"same-type constraints within an equiv. class are out-of-order");
289-
} else {
290-
// Otherwise, the concrete types must match up.
291-
assert(prevReqt.getSecondType()->isEqual(reqt.getSecondType()) &&
292-
"inconsistent concrete same-type constraints in equiv. class");
293-
}
294-
}
295-
296-
// From here on, we only care about cases where the previous and current
297-
// requirements have the same left-hand side.
298-
if (compareLHS != 0) continue;
299-
300-
// Check ordering of requirement kinds.
301-
assert((getRequirementKindOrder(prevReqt.getKind()) <=
302-
getRequirementKindOrder(reqt.getKind())) &&
303-
"Requirements for a given kind are out-of-order");
304-
305-
// From here on, we only care about the same requirement kind.
306-
if (prevReqt.getKind() != reqt.getKind()) continue;
307-
308-
assert(reqt.getKind() == RequirementKind::Conformance &&
309-
"Only conformance requirements can have multiples");
310-
311-
auto prevProto = prevReqt.getProtocolDecl();
312-
auto proto = reqt.getProtocolDecl();
313-
assert(TypeDecl::compare(prevProto, proto) < 0 &&
314-
"Out-of-order conformance requirements");
315-
}
316-
#endif
317-
318197
return CanGenericSignature(canSig);
319198
}
320199

@@ -519,7 +398,19 @@ bool GenericSignatureImpl::areSameTypeParameterInContext(Type type1,
519398
if (type1.getPointer() == type2.getPointer())
520399
return true;
521400

522-
auto &builder = *getGenericSignatureBuilder();
401+
return areSameTypeParameterInContext(type1, type2,
402+
*getGenericSignatureBuilder());
403+
}
404+
405+
bool GenericSignatureImpl::areSameTypeParameterInContext(Type type1,
406+
Type type2,
407+
GenericSignatureBuilder &builder) const {
408+
assert(type1->isTypeParameter());
409+
assert(type2->isTypeParameter());
410+
411+
if (type1.getPointer() == type2.getPointer())
412+
return true;
413+
523414
auto equivClass1 =
524415
builder.resolveEquivalenceClass(
525416
type1,

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7948,6 +7948,129 @@ void GenericSignatureBuilder::addGenericSignature(GenericSignature sig) {
79487948
addRequirement(reqt, FloatingRequirementSource::forAbstract(), nullptr);
79497949
}
79507950

7951+
#ifndef NDEBUG
7952+
7953+
/// Determine the canonical ordering of requirements.
7954+
static unsigned getRequirementKindOrder(RequirementKind kind) {
7955+
switch (kind) {
7956+
case RequirementKind::Conformance: return 2;
7957+
case RequirementKind::Superclass: return 0;
7958+
case RequirementKind::SameType: return 3;
7959+
case RequirementKind::Layout: return 1;
7960+
}
7961+
llvm_unreachable("unhandled kind");
7962+
}
7963+
7964+
static void checkGenericSignature(CanGenericSignature canSig,
7965+
GenericSignatureBuilder &builder) {
7966+
PrettyStackTraceGenericSignature debugStack("checking", canSig);
7967+
7968+
auto canonicalRequirements = canSig->getRequirements();
7969+
7970+
// Check that the signature is canonical.
7971+
for (unsigned idx : indices(canonicalRequirements)) {
7972+
debugStack.setRequirement(idx);
7973+
7974+
const auto &reqt = canonicalRequirements[idx];
7975+
7976+
// Left-hand side must be canonical in its context.
7977+
// Check canonicalization of requirement itself.
7978+
switch (reqt.getKind()) {
7979+
case RequirementKind::Superclass:
7980+
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) &&
7981+
"Left-hand side is not canonical");
7982+
assert(canSig->isCanonicalTypeInContext(reqt.getSecondType(), builder) &&
7983+
"Superclass type isn't canonical in its own context");
7984+
break;
7985+
7986+
case RequirementKind::Layout:
7987+
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) &&
7988+
"Left-hand side is not canonical");
7989+
break;
7990+
7991+
case RequirementKind::SameType: {
7992+
auto isCanonicalAnchor = [&](Type type) {
7993+
if (auto *dmt = type->getAs<DependentMemberType>())
7994+
return canSig->isCanonicalTypeInContext(dmt->getBase(), builder);
7995+
return type->is<GenericTypeParamType>();
7996+
};
7997+
7998+
auto firstType = reqt.getFirstType();
7999+
auto secondType = reqt.getSecondType();
8000+
assert(isCanonicalAnchor(firstType));
8001+
8002+
if (reqt.getSecondType()->isTypeParameter()) {
8003+
assert(isCanonicalAnchor(secondType));
8004+
assert(compareDependentTypes(firstType, secondType) < 0 &&
8005+
"Out-of-order type parameters in same-type constraint");
8006+
} else {
8007+
assert(canSig->isCanonicalTypeInContext(secondType) &&
8008+
"Concrete same-type isn't canonical in its own context");
8009+
}
8010+
break;
8011+
}
8012+
8013+
case RequirementKind::Conformance:
8014+
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) &&
8015+
"Left-hand side is not canonical");
8016+
assert(reqt.getFirstType()->isTypeParameter() &&
8017+
"Left-hand side must be a type parameter");
8018+
assert(isa<ProtocolType>(reqt.getSecondType().getPointer()) &&
8019+
"Right-hand side of conformance isn't a protocol type");
8020+
break;
8021+
}
8022+
8023+
// From here on, we're only interested in requirements beyond the first.
8024+
if (idx == 0) continue;
8025+
8026+
// Make sure that the left-hand sides are in nondecreasing order.
8027+
const auto &prevReqt = canonicalRequirements[idx-1];
8028+
int compareLHS =
8029+
compareDependentTypes(prevReqt.getFirstType(), reqt.getFirstType());
8030+
assert(compareLHS <= 0 && "Out-of-order left-hand sides");
8031+
8032+
// If we have two same-type requirements where the left-hand sides differ
8033+
// but fall into the same equivalence class, we can check the form.
8034+
if (compareLHS < 0 && reqt.getKind() == RequirementKind::SameType &&
8035+
prevReqt.getKind() == RequirementKind::SameType &&
8036+
canSig->areSameTypeParameterInContext(prevReqt.getFirstType(),
8037+
reqt.getFirstType(),
8038+
builder)) {
8039+
// If it's a it's a type parameter, make sure the equivalence class is
8040+
// wired together sanely.
8041+
if (prevReqt.getSecondType()->isTypeParameter()) {
8042+
assert(prevReqt.getSecondType()->isEqual(reqt.getFirstType()) &&
8043+
"same-type constraints within an equiv. class are out-of-order");
8044+
} else {
8045+
// Otherwise, the concrete types must match up.
8046+
assert(prevReqt.getSecondType()->isEqual(reqt.getSecondType()) &&
8047+
"inconsistent concrete same-type constraints in equiv. class");
8048+
}
8049+
}
8050+
8051+
// From here on, we only care about cases where the previous and current
8052+
// requirements have the same left-hand side.
8053+
if (compareLHS != 0) continue;
8054+
8055+
// Check ordering of requirement kinds.
8056+
assert((getRequirementKindOrder(prevReqt.getKind()) <=
8057+
getRequirementKindOrder(reqt.getKind())) &&
8058+
"Requirements for a given kind are out-of-order");
8059+
8060+
// From here on, we only care about the same requirement kind.
8061+
if (prevReqt.getKind() != reqt.getKind()) continue;
8062+
8063+
assert(reqt.getKind() == RequirementKind::Conformance &&
8064+
"Only conformance requirements can have multiples");
8065+
8066+
auto prevProto = prevReqt.getProtocolDecl();
8067+
auto proto = reqt.getProtocolDecl();
8068+
assert(TypeDecl::compare(prevProto, proto) < 0 &&
8069+
"Out-of-order conformance requirements");
8070+
}
8071+
}
8072+
#endif
8073+
79518074
GenericSignature GenericSignatureBuilder::computeGenericSignature(
79528075
bool allowConcreteGenericParams,
79538076
bool allowBuilderToMove) && {
@@ -7961,6 +8084,12 @@ GenericSignature GenericSignatureBuilder::computeGenericSignature(
79618084
// Form the generic signature.
79628085
auto sig = GenericSignature::get(getGenericParams(), requirements);
79638086

8087+
#ifndef NDEBUG
8088+
if (!Impl->HadAnyError) {
8089+
checkGenericSignature(sig.getCanonicalSignature(), *this);
8090+
}
8091+
#endif
8092+
79648093
// When we can, move this generic signature builder to make it the canonical
79658094
// builder, rather than constructing a new generic signature builder that
79668095
// will produce the same thing.

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,13 +2452,10 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24522452
requirementsSig->print(llvm::errs());
24532453
llvm::errs() << "\n";
24542454

2455-
// Note: One cannot canonicalize a requirement signature, because
2456-
// requirement signatures are necessarily missing requirements.
24572455
llvm::errs() << "Canonical requirement signature: ";
24582456
auto canRequirementSig =
24592457
CanGenericSignature::getCanonical(requirementsSig->getGenericParams(),
2460-
requirementsSig->getRequirements(),
2461-
/*skipValidation=*/true);
2458+
requirementsSig->getRequirements());
24622459
canRequirementSig->print(llvm::errs());
24632460
llvm::errs() << "\n";
24642461
}

0 commit comments

Comments
 (0)