mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Previously we would look for a derived source before an explicit one, on account of the explicit one possibly being redundant. However, the presence of 'self-derived' sources meant that we had to call getMinimalConformanceSource() to ensure the derived sources were actually usable and would not produce an infinite conformance access path. I'd like to remove getMinimalConformanceSource() now that we have an alternate algorithm to identify redundant explicit requirements. Instead, we can handle the explicit case first, by checking for a conformance requirement in the generic signature -- its presence means it was not redundant, by construction. Then once we handle that case, we know we're going to use a derived source, and finding the shortest one seems to be good enough. This fixes the IRGen crash in https://bugs.swift.org/browse/SR-11153; the requirement signatures in that test still have unnecessary same-type requirements printed, so I added a separate RUN: line for those, and it's marked as known-failing with 'not %FileCheck'.
1019 lines
35 KiB
C++
1019 lines
35 KiB
C++
//===--- GenericSignature.cpp - Generic Signature AST ---------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the GenericSignature class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "GenericSignatureBuilderImpl.h"
|
|
#include "swift/AST/GenericSignature.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/GenericSignatureBuilder.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/Basic/STLExtras.h"
|
|
#include <functional>
|
|
|
|
using namespace swift;
|
|
|
|
void ConformanceAccessPath::print(raw_ostream &out) const {
|
|
llvm::interleave(
|
|
begin(), end(),
|
|
[&](const Entry &entry) {
|
|
entry.first.print(out);
|
|
out << ": " << entry.second->getName();
|
|
},
|
|
[&] { out << " -> "; });
|
|
}
|
|
|
|
void ConformanceAccessPath::dump() const {
|
|
print(llvm::errs());
|
|
llvm::errs() << "\n";
|
|
}
|
|
|
|
GenericSignatureImpl::GenericSignatureImpl(
|
|
TypeArrayView<GenericTypeParamType> params,
|
|
ArrayRef<Requirement> requirements, bool isKnownCanonical)
|
|
: NumGenericParams(params.size()), NumRequirements(requirements.size()),
|
|
CanonicalSignatureOrASTContext() {
|
|
std::uninitialized_copy(params.begin(), params.end(),
|
|
getTrailingObjects<Type>());
|
|
std::uninitialized_copy(requirements.begin(), requirements.end(),
|
|
getTrailingObjects<Requirement>());
|
|
|
|
#ifndef NDEBUG
|
|
// Make sure generic parameters are in the right order, and
|
|
// none are missing.
|
|
unsigned depth = 0;
|
|
unsigned count = 0;
|
|
for (auto param : params) {
|
|
if (param->getDepth() != depth) {
|
|
assert(param->getDepth() > depth && "Generic parameter depth mismatch");
|
|
depth = param->getDepth();
|
|
count = 0;
|
|
}
|
|
assert(param->getIndex() == count && "Generic parameter index mismatch");
|
|
++count;
|
|
}
|
|
#endif
|
|
|
|
if (isKnownCanonical)
|
|
CanonicalSignatureOrASTContext =
|
|
&GenericSignature::getASTContext(params, requirements);
|
|
}
|
|
|
|
TypeArrayView<GenericTypeParamType>
|
|
GenericSignatureImpl::getInnermostGenericParams() const {
|
|
const auto params = getGenericParams();
|
|
|
|
const unsigned maxDepth = params.back()->getDepth();
|
|
if (params.front()->getDepth() == maxDepth)
|
|
return params;
|
|
|
|
// There is a depth change. Count the number of elements
|
|
// to slice off the front.
|
|
unsigned sliceCount = params.size() - 1;
|
|
while (true) {
|
|
if (params[sliceCount - 1]->getDepth() != maxDepth)
|
|
break;
|
|
--sliceCount;
|
|
}
|
|
|
|
return params.slice(sliceCount);
|
|
}
|
|
|
|
void GenericSignatureImpl::forEachParam(
|
|
llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const {
|
|
// Figure out which generic parameters are concrete or same-typed to another
|
|
// type parameter.
|
|
auto genericParams = getGenericParams();
|
|
auto genericParamsAreCanonical =
|
|
SmallVector<bool, 4>(genericParams.size(), true);
|
|
|
|
for (auto req : getRequirements()) {
|
|
if (req.getKind() != RequirementKind::SameType) continue;
|
|
|
|
GenericTypeParamType *gp;
|
|
if (auto secondGP = req.getSecondType()->getAs<GenericTypeParamType>()) {
|
|
// If two generic parameters are same-typed, then the right-hand one
|
|
// is non-canonical.
|
|
assert(req.getFirstType()->is<GenericTypeParamType>());
|
|
gp = secondGP;
|
|
} else {
|
|
// Otherwise, the right-hand side is an associated type or concrete type,
|
|
// and the left-hand one is non-canonical.
|
|
gp = req.getFirstType()->getAs<GenericTypeParamType>();
|
|
if (!gp) continue;
|
|
|
|
// If an associated type is same-typed, it doesn't constrain the generic
|
|
// parameter itself. That is, if T == U.Foo, then T is canonical, whereas
|
|
// U.Foo is not.
|
|
if (req.getSecondType()->isTypeParameter()) continue;
|
|
}
|
|
|
|
unsigned index = GenericParamKey(gp).findIndexIn(genericParams);
|
|
genericParamsAreCanonical[index] = false;
|
|
}
|
|
|
|
// Call the callback with each parameter and the result of the above analysis.
|
|
for (auto index : indices(genericParams))
|
|
callback(genericParams[index], genericParamsAreCanonical[index]);
|
|
}
|
|
|
|
bool GenericSignatureImpl::areAllParamsConcrete() const {
|
|
unsigned numConcreteGenericParams = 0;
|
|
for (const auto &req : getRequirements()) {
|
|
if (req.getKind() != RequirementKind::SameType) continue;
|
|
if (!req.getFirstType()->is<GenericTypeParamType>()) continue;
|
|
if (req.getSecondType()->isTypeParameter()) continue;
|
|
|
|
++numConcreteGenericParams;
|
|
}
|
|
|
|
return numConcreteGenericParams == getGenericParams().size();
|
|
}
|
|
|
|
ASTContext &GenericSignature::getASTContext(
|
|
TypeArrayView<GenericTypeParamType> params,
|
|
ArrayRef<swift::Requirement> requirements) {
|
|
// The params and requirements cannot both be empty.
|
|
if (!params.empty())
|
|
return params.front()->getASTContext();
|
|
else
|
|
return requirements.front().getFirstType()->getASTContext();
|
|
}
|
|
|
|
GenericSignatureBuilder *
|
|
GenericSignatureImpl::getGenericSignatureBuilder() const {
|
|
// The generic signature builder is associated with the canonical signature.
|
|
if (!isCanonical())
|
|
return getCanonicalSignature()->getGenericSignatureBuilder();
|
|
|
|
// generic signature builders are stored on the ASTContext.
|
|
return getASTContext().getOrCreateGenericSignatureBuilder(
|
|
CanGenericSignature(this));
|
|
}
|
|
|
|
bool GenericSignatureImpl::isEqual(GenericSignature Other) const {
|
|
return getCanonicalSignature() == Other.getCanonicalSignature();
|
|
}
|
|
|
|
bool GenericSignatureImpl::isCanonical() const {
|
|
if (CanonicalSignatureOrASTContext.is<ASTContext *>())
|
|
return true;
|
|
return getCanonicalSignature().getPointer() == this;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
/// Determine the canonical ordering of requirements.
|
|
static unsigned getRequirementKindOrder(RequirementKind kind) {
|
|
switch (kind) {
|
|
case RequirementKind::Conformance: return 2;
|
|
case RequirementKind::Superclass: return 0;
|
|
case RequirementKind::SameType: return 3;
|
|
case RequirementKind::Layout: return 1;
|
|
}
|
|
llvm_unreachable("unhandled kind");
|
|
}
|
|
#endif
|
|
|
|
CanGenericSignature
|
|
CanGenericSignature::getCanonical(TypeArrayView<GenericTypeParamType> params,
|
|
ArrayRef<Requirement> requirements,
|
|
bool skipValidation) {
|
|
// Canonicalize the parameters and requirements.
|
|
SmallVector<GenericTypeParamType*, 8> canonicalParams;
|
|
canonicalParams.reserve(params.size());
|
|
for (auto param : params) {
|
|
canonicalParams.push_back(cast<GenericTypeParamType>(param->getCanonicalType()));
|
|
}
|
|
|
|
SmallVector<Requirement, 8> canonicalRequirements;
|
|
canonicalRequirements.reserve(requirements.size());
|
|
for (auto &reqt : requirements)
|
|
canonicalRequirements.push_back(reqt.getCanonical());
|
|
|
|
(void)skipValidation;
|
|
auto canSig = get(canonicalParams, canonicalRequirements,
|
|
/*isKnownCanonical=*/true);
|
|
|
|
#ifndef NDEBUG
|
|
if (skipValidation)
|
|
return CanGenericSignature(canSig);
|
|
|
|
PrettyStackTraceGenericSignature debugStack("canonicalizing", canSig);
|
|
|
|
// Check that the signature is canonical.
|
|
for (unsigned idx : indices(canonicalRequirements)) {
|
|
debugStack.setRequirement(idx);
|
|
|
|
const auto &reqt = canonicalRequirements[idx];
|
|
|
|
// Left-hand side must be canonical in its context.
|
|
// Check canonicalization of requirement itself.
|
|
switch (reqt.getKind()) {
|
|
case RequirementKind::Superclass:
|
|
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType()) &&
|
|
"Left-hand side is not canonical");
|
|
assert(canSig->isCanonicalTypeInContext(reqt.getSecondType()) &&
|
|
"Superclass type isn't canonical in its own context");
|
|
break;
|
|
|
|
case RequirementKind::Layout:
|
|
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType()) &&
|
|
"Left-hand side is not canonical");
|
|
break;
|
|
|
|
case RequirementKind::SameType: {
|
|
auto isCanonicalAnchor = [&](Type type) {
|
|
if (auto *dmt = type->getAs<DependentMemberType>())
|
|
return canSig->isCanonicalTypeInContext(dmt->getBase());
|
|
return type->is<GenericTypeParamType>();
|
|
};
|
|
|
|
auto firstType = reqt.getFirstType();
|
|
auto secondType = reqt.getSecondType();
|
|
assert(isCanonicalAnchor(firstType));
|
|
|
|
if (reqt.getSecondType()->isTypeParameter()) {
|
|
assert(isCanonicalAnchor(secondType));
|
|
assert(compareDependentTypes(firstType, secondType) < 0 &&
|
|
"Out-of-order type parameters in same-type constraint");
|
|
} else {
|
|
assert(canSig->isCanonicalTypeInContext(secondType) &&
|
|
"Concrete same-type isn't canonical in its own context");
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RequirementKind::Conformance:
|
|
assert(reqt.getFirstType()->isTypeParameter() &&
|
|
"Left-hand side must be a type parameter");
|
|
assert(isa<ProtocolType>(reqt.getSecondType().getPointer()) &&
|
|
"Right-hand side of conformance isn't a protocol type");
|
|
break;
|
|
}
|
|
|
|
// From here on, we're only interested in requirements beyond the first.
|
|
if (idx == 0) continue;
|
|
|
|
// Make sure that the left-hand sides are in nondecreasing order.
|
|
const auto &prevReqt = canonicalRequirements[idx-1];
|
|
int compareLHS =
|
|
compareDependentTypes(prevReqt.getFirstType(), reqt.getFirstType());
|
|
assert(compareLHS <= 0 && "Out-of-order left-hand sides");
|
|
|
|
// If we have two same-type requirements where the left-hand sides differ
|
|
// but fall into the same equivalence class, we can check the form.
|
|
if (compareLHS < 0 && reqt.getKind() == RequirementKind::SameType &&
|
|
prevReqt.getKind() == RequirementKind::SameType &&
|
|
canSig->areSameTypeParameterInContext(prevReqt.getFirstType(),
|
|
reqt.getFirstType())) {
|
|
// If it's a it's a type parameter, make sure the equivalence class is
|
|
// wired together sanely.
|
|
if (prevReqt.getSecondType()->isTypeParameter()) {
|
|
assert(prevReqt.getSecondType()->isEqual(reqt.getFirstType()) &&
|
|
"same-type constraints within an equiv. class are out-of-order");
|
|
} else {
|
|
// Otherwise, the concrete types must match up.
|
|
assert(prevReqt.getSecondType()->isEqual(reqt.getSecondType()) &&
|
|
"inconsistent concrete same-type constraints in equiv. class");
|
|
}
|
|
}
|
|
|
|
// From here on, we only care about cases where the previous and current
|
|
// requirements have the same left-hand side.
|
|
if (compareLHS != 0) continue;
|
|
|
|
// Check ordering of requirement kinds.
|
|
assert((getRequirementKindOrder(prevReqt.getKind()) <=
|
|
getRequirementKindOrder(reqt.getKind())) &&
|
|
"Requirements for a given kind are out-of-order");
|
|
|
|
// From here on, we only care about the same requirement kind.
|
|
if (prevReqt.getKind() != reqt.getKind()) continue;
|
|
|
|
assert(reqt.getKind() == RequirementKind::Conformance &&
|
|
"Only conformance requirements can have multiples");
|
|
|
|
auto prevProto = prevReqt.getProtocolDecl();
|
|
auto proto = reqt.getProtocolDecl();
|
|
assert(TypeDecl::compare(prevProto, proto) < 0 &&
|
|
"Out-of-order conformance requirements");
|
|
}
|
|
#endif
|
|
|
|
return CanGenericSignature(canSig);
|
|
}
|
|
|
|
CanGenericSignature GenericSignature::getCanonicalSignature() const {
|
|
// If the underlying pointer is null, return `CanGenericSignature()`.
|
|
if (isNull())
|
|
return CanGenericSignature();
|
|
// Otherwise, return the canonical signature of the underlying pointer.
|
|
return getPointer()->getCanonicalSignature();
|
|
}
|
|
|
|
CanGenericSignature GenericSignatureImpl::getCanonicalSignature() const {
|
|
// If we haven't computed the canonical signature yet, do so now.
|
|
if (CanonicalSignatureOrASTContext.isNull()) {
|
|
// Compute the canonical signature.
|
|
auto canSig = CanGenericSignature::getCanonical(getGenericParams(),
|
|
getRequirements());
|
|
|
|
// Record either the canonical signature or an indication that
|
|
// this is the canonical signature.
|
|
if (canSig.getPointer() != this)
|
|
CanonicalSignatureOrASTContext = canSig.getPointer();
|
|
else
|
|
CanonicalSignatureOrASTContext = &getGenericParams()[0]->getASTContext();
|
|
|
|
// Return the canonical signature.
|
|
return canSig;
|
|
}
|
|
|
|
// A stored ASTContext indicates that this is the canonical
|
|
// signature.
|
|
if (CanonicalSignatureOrASTContext.is<ASTContext *>())
|
|
return CanGenericSignature(this);
|
|
|
|
// Otherwise, return the stored canonical signature.
|
|
return CanGenericSignature(
|
|
CanonicalSignatureOrASTContext.get<const GenericSignatureImpl *>());
|
|
}
|
|
|
|
GenericEnvironment *GenericSignatureImpl::getGenericEnvironment() const {
|
|
if (GenericEnv == nullptr) {
|
|
auto *builder = getGenericSignatureBuilder();
|
|
const auto impl = const_cast<GenericSignatureImpl *>(this);
|
|
impl->GenericEnv = GenericEnvironment::getIncomplete(this, builder);
|
|
}
|
|
|
|
return GenericEnv;
|
|
}
|
|
|
|
ASTContext &GenericSignatureImpl::getASTContext() const {
|
|
// Canonical signatures store the ASTContext directly.
|
|
if (auto ctx = CanonicalSignatureOrASTContext.dyn_cast<ASTContext *>())
|
|
return *ctx;
|
|
|
|
// For everything else, just get it from the generic parameter.
|
|
return GenericSignature::getASTContext(getGenericParams(), getRequirements());
|
|
}
|
|
|
|
ProtocolConformanceRef
|
|
GenericSignatureImpl::lookupConformance(CanType type,
|
|
ProtocolDecl *proto) const {
|
|
// FIXME: Actually implement this properly.
|
|
auto *M = proto->getParentModule();
|
|
|
|
if (type->isTypeParameter())
|
|
return ProtocolConformanceRef(proto);
|
|
|
|
return M->lookupConformance(type, proto);
|
|
}
|
|
|
|
bool GenericSignatureImpl::requiresClass(Type type) const {
|
|
assert(type->isTypeParameter() &&
|
|
"Only type parameters can have superclass requirements");
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
type,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
if (!equivClass) return false;
|
|
|
|
// If this type was mapped to a concrete type, then there is no
|
|
// requirement.
|
|
if (equivClass->concreteType) return false;
|
|
|
|
// If there is a layout constraint, it might be a class.
|
|
if (equivClass->layout && equivClass->layout->isClass()) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Determine the superclass bound on the given dependent type.
|
|
Type GenericSignatureImpl::getSuperclassBound(Type type) const {
|
|
assert(type->isTypeParameter() &&
|
|
"Only type parameters can have superclass requirements");
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
type,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
if (!equivClass) return nullptr;
|
|
|
|
// If this type was mapped to a concrete type, then there is no
|
|
// requirement.
|
|
if (equivClass->concreteType) return nullptr;
|
|
|
|
// Retrieve the superclass bound.
|
|
return equivClass->superclass;
|
|
}
|
|
|
|
/// Determine the set of protocols to which the given type parameter is
|
|
/// required to conform.
|
|
GenericSignature::RequiredProtocols
|
|
GenericSignatureImpl::getRequiredProtocols(Type type) const {
|
|
assert(type->isTypeParameter() && "Expected a type parameter");
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
type,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
if (!equivClass) return { };
|
|
|
|
// If this type parameter was mapped to a concrete type, then there
|
|
// are no requirements.
|
|
if (equivClass->concreteType) return { };
|
|
|
|
// Retrieve the protocols to which this type conforms.
|
|
GenericSignature::RequiredProtocols result;
|
|
for (const auto &conforms : equivClass->conformsTo)
|
|
result.push_back(conforms.first);
|
|
|
|
// Canonicalize the resulting set of protocols.
|
|
ProtocolType::canonicalizeProtocols(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool GenericSignatureImpl::requiresProtocol(Type type,
|
|
ProtocolDecl *proto) const {
|
|
assert(type->isTypeParameter() && "Expected a type parameter");
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
type,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
if (!equivClass) return false;
|
|
|
|
// FIXME: Optionally deal with concrete conformances here
|
|
// or have a separate method do that additionally?
|
|
//
|
|
// If this type parameter was mapped to a concrete type, then there
|
|
// are no requirements.
|
|
if (equivClass->concreteType) return false;
|
|
|
|
// Check whether the representative conforms to this protocol.
|
|
return equivClass->conformsTo.count(proto) > 0;
|
|
}
|
|
|
|
/// Determine whether the given dependent type is equal to a concrete type.
|
|
bool GenericSignatureImpl::isConcreteType(Type type) const {
|
|
return bool(getConcreteType(type));
|
|
}
|
|
|
|
/// Return the concrete type that the given type parameter is constrained to,
|
|
/// or the null Type if it is not the subject of a concrete same-type
|
|
/// constraint.
|
|
Type GenericSignatureImpl::getConcreteType(Type type) const {
|
|
assert(type->isTypeParameter() && "Expected a type parameter");
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
type,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
if (!equivClass) return Type();
|
|
|
|
return equivClass->concreteType;
|
|
}
|
|
|
|
LayoutConstraint GenericSignatureImpl::getLayoutConstraint(Type type) const {
|
|
assert(type->isTypeParameter() &&
|
|
"Only type parameters can have layout constraints");
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
type,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
if (!equivClass) return LayoutConstraint();
|
|
|
|
return equivClass->layout;
|
|
}
|
|
|
|
bool GenericSignatureImpl::areSameTypeParameterInContext(Type type1,
|
|
Type type2) const {
|
|
assert(type1->isTypeParameter());
|
|
assert(type2->isTypeParameter());
|
|
|
|
if (type1.getPointer() == type2.getPointer())
|
|
return true;
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass1 =
|
|
builder.resolveEquivalenceClass(
|
|
type1,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
assert(equivClass1 && "not a valid dependent type of this signature?");
|
|
|
|
auto equivClass2 =
|
|
builder.resolveEquivalenceClass(
|
|
type2,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
assert(equivClass2 && "not a valid dependent type of this signature?");
|
|
|
|
return equivClass1 == equivClass2;
|
|
}
|
|
|
|
bool GenericSignatureImpl::isRequirementSatisfied(
|
|
Requirement requirement) const {
|
|
auto GSB = getGenericSignatureBuilder();
|
|
|
|
auto firstType = requirement.getFirstType();
|
|
auto canFirstType = getCanonicalTypeInContext(firstType);
|
|
|
|
switch (requirement.getKind()) {
|
|
case RequirementKind::Conformance: {
|
|
auto *protocol = requirement.getProtocolDecl();
|
|
|
|
if (canFirstType->isTypeParameter())
|
|
return requiresProtocol(canFirstType, protocol);
|
|
else
|
|
return (bool)GSB->lookupConformance(/*dependentType=*/CanType(),
|
|
canFirstType, protocol);
|
|
}
|
|
|
|
case RequirementKind::SameType: {
|
|
auto canSecondType = getCanonicalTypeInContext(requirement.getSecondType());
|
|
return canFirstType->isEqual(canSecondType);
|
|
}
|
|
|
|
case RequirementKind::Superclass: {
|
|
auto requiredSuperclass =
|
|
getCanonicalTypeInContext(requirement.getSecondType());
|
|
|
|
// The requirement could be in terms of type parameters like a user-written
|
|
// requirement, but it could also be in terms of concrete types if it has
|
|
// been substituted/otherwise 'resolved', so we need to handle both.
|
|
auto baseType = canFirstType;
|
|
if (baseType->isTypeParameter()) {
|
|
auto directSuperclass = getSuperclassBound(baseType);
|
|
if (!directSuperclass)
|
|
return false;
|
|
|
|
baseType = getCanonicalTypeInContext(directSuperclass);
|
|
}
|
|
|
|
return requiredSuperclass->isExactSuperclassOf(baseType);
|
|
}
|
|
|
|
case RequirementKind::Layout: {
|
|
auto requiredLayout = requirement.getLayoutConstraint();
|
|
|
|
if (canFirstType->isTypeParameter()) {
|
|
if (auto layout = getLayoutConstraint(canFirstType))
|
|
return static_cast<bool>(layout.merge(requiredLayout));
|
|
|
|
return false;
|
|
}
|
|
|
|
// The requirement is on a concrete type, so it's either globally correct
|
|
// or globally incorrect, independent of this generic context. The latter
|
|
// case should be diagnosed elsewhere, so let's assume it's correct.
|
|
return true;
|
|
}
|
|
}
|
|
llvm_unreachable("unhandled kind");
|
|
}
|
|
|
|
SmallVector<Requirement, 4> GenericSignatureImpl::requirementsNotSatisfiedBy(
|
|
GenericSignature otherSig) const {
|
|
SmallVector<Requirement, 4> result;
|
|
|
|
// If the signatures match by pointer, all requirements are satisfied.
|
|
if (otherSig.getPointer() == this) return result;
|
|
|
|
// If there is no other signature, no requirements are satisfied.
|
|
if (!otherSig){
|
|
const auto reqs = getRequirements();
|
|
result.append(reqs.begin(), reqs.end());
|
|
return result;
|
|
}
|
|
|
|
// If the canonical signatures are equal, all requirements are satisfied.
|
|
if (getCanonicalSignature() == otherSig->getCanonicalSignature())
|
|
return result;
|
|
|
|
// Find the requirements that aren't satisfied.
|
|
for (const auto &req : getRequirements()) {
|
|
if (!otherSig->isRequirementSatisfied(req))
|
|
result.push_back(req);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool GenericSignatureImpl::isCanonicalTypeInContext(Type type) const {
|
|
// If the type isn't independently canonical, it's certainly not canonical
|
|
// in this context.
|
|
if (!type->isCanonical())
|
|
return false;
|
|
|
|
// All the contextual canonicality rules apply to type parameters, so if the
|
|
// type doesn't involve any type parameters, it's already canonical.
|
|
if (!type->hasTypeParameter())
|
|
return true;
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
return isCanonicalTypeInContext(type, builder);
|
|
}
|
|
|
|
bool GenericSignatureImpl::isCanonicalTypeInContext(
|
|
Type type, GenericSignatureBuilder &builder) const {
|
|
// If the type isn't independently canonical, it's certainly not canonical
|
|
// in this context.
|
|
if (!type->isCanonical())
|
|
return false;
|
|
|
|
// All the contextual canonicality rules apply to type parameters, so if the
|
|
// type doesn't involve any type parameters, it's already canonical.
|
|
if (!type->hasTypeParameter())
|
|
return true;
|
|
|
|
// Look for non-canonical type parameters.
|
|
return !type.findIf([&](Type component) -> bool {
|
|
if (!component->isTypeParameter()) return false;
|
|
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
Type(component),
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
if (!equivClass) return false;
|
|
|
|
return (equivClass->concreteType ||
|
|
!component->isEqual(equivClass->getAnchor(builder,
|
|
getGenericParams())));
|
|
});
|
|
}
|
|
|
|
CanType GenericSignatureImpl::getCanonicalTypeInContext(
|
|
Type type, GenericSignatureBuilder &builder) const {
|
|
type = type->getCanonicalType();
|
|
|
|
// All the contextual canonicality rules apply to type parameters, so if the
|
|
// type doesn't involve any type parameters, it's already canonical.
|
|
if (!type->hasTypeParameter())
|
|
return CanType(type);
|
|
|
|
// Replace non-canonical type parameters.
|
|
type = type.transformRec([&](TypeBase *component) -> Optional<Type> {
|
|
if (!isa<GenericTypeParamType>(component) &&
|
|
!isa<DependentMemberType>(component))
|
|
return None;
|
|
|
|
// Find the equivalence class for this dependent type.
|
|
auto resolved = builder.maybeResolveEquivalenceClass(
|
|
Type(component),
|
|
ArchetypeResolutionKind::CompleteWellFormed,
|
|
/*wantExactPotentialArchetype=*/false);
|
|
if (!resolved) return None;
|
|
|
|
if (auto concrete = resolved.getAsConcreteType())
|
|
return getCanonicalTypeInContext(concrete, builder);
|
|
|
|
auto equivClass = resolved.getEquivalenceClass(builder);
|
|
if (!equivClass) return None;
|
|
|
|
if (equivClass->concreteType) {
|
|
return getCanonicalTypeInContext(equivClass->concreteType, builder);
|
|
}
|
|
|
|
return equivClass->getAnchor(builder, getGenericParams());
|
|
});
|
|
|
|
auto result = type->getCanonicalType();
|
|
|
|
assert(isCanonicalTypeInContext(result, builder));
|
|
return result;
|
|
}
|
|
|
|
CanType GenericSignatureImpl::getCanonicalTypeInContext(Type type) const {
|
|
type = type->getCanonicalType();
|
|
|
|
// All the contextual canonicality rules apply to type parameters, so if the
|
|
// type doesn't involve any type parameters, it's already canonical.
|
|
if (!type->hasTypeParameter())
|
|
return CanType(type);
|
|
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
return getCanonicalTypeInContext(type, builder);
|
|
}
|
|
|
|
ArrayRef<CanTypeWrapper<GenericTypeParamType>>
|
|
CanGenericSignature::getGenericParams() const{
|
|
auto params = getPointer()->getGenericParams().getOriginalArray();
|
|
auto base = static_cast<const CanTypeWrapper<GenericTypeParamType>*>(
|
|
params.data());
|
|
return {base, params.size()};
|
|
}
|
|
|
|
namespace {
|
|
typedef GenericSignatureBuilder::RequirementSource RequirementSource;
|
|
|
|
template<typename T>
|
|
using GSBConstraint = GenericSignatureBuilder::Constraint<T>;
|
|
} // end anonymous namespace
|
|
|
|
/// Determine whether there is a conformance of the given
|
|
/// subject type to the given protocol within the given set of explicit
|
|
/// requirements.
|
|
static bool hasConformanceInSignature(ArrayRef<Requirement> requirements,
|
|
Type subjectType,
|
|
ProtocolDecl *proto) {
|
|
// Make sure this requirement exists in the requirement signature.
|
|
for (const auto &req: requirements) {
|
|
if (req.getKind() == RequirementKind::Conformance &&
|
|
req.getFirstType()->isEqual(subjectType) &&
|
|
req.getProtocolDecl() == proto) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ConformanceAccessPath
|
|
GenericSignatureImpl::getConformanceAccessPath(Type type,
|
|
ProtocolDecl *protocol) const {
|
|
assert(type->isTypeParameter() && "not a type parameter");
|
|
|
|
// Look up the equivalence class for this type.
|
|
auto &builder = *getGenericSignatureBuilder();
|
|
auto equivClass =
|
|
builder.resolveEquivalenceClass(
|
|
type,
|
|
ArchetypeResolutionKind::CompleteWellFormed);
|
|
|
|
assert(!equivClass->concreteType &&
|
|
"Concrete types don't have conformance access paths");
|
|
|
|
auto cached = equivClass->conformanceAccessPathCache.find(protocol);
|
|
if (cached != equivClass->conformanceAccessPathCache.end())
|
|
return cached->second;
|
|
|
|
// Dig out the conformance of this type to the given protocol, because we
|
|
// want its requirement source.
|
|
auto conforms = equivClass->conformsTo.find(protocol);
|
|
assert(conforms != equivClass->conformsTo.end());
|
|
|
|
auto rootType = equivClass->getAnchor(builder, { });
|
|
if (hasConformanceInSignature(getRequirements(), rootType, protocol)) {
|
|
ConformanceAccessPath::Entry root(rootType, protocol);
|
|
ArrayRef<ConformanceAccessPath::Entry> path(root);
|
|
|
|
ConformanceAccessPath result(builder.getASTContext().AllocateCopy(path));
|
|
equivClass->conformanceAccessPathCache.insert({protocol, result});
|
|
|
|
return result;
|
|
}
|
|
|
|
// This conformance comes from a derived source.
|
|
//
|
|
// To recover this the conformance, we recursively recover the conformance
|
|
// of the shortest parent type to the parent protocol first.
|
|
Type shortestParentType;
|
|
Type shortestSubjectType;
|
|
ProtocolDecl *shortestParentProto = nullptr;
|
|
|
|
auto isShortestPath = [&](Type parentType,
|
|
Type subjectType,
|
|
ProtocolDecl *parentProto) -> bool {
|
|
if (!shortestParentType)
|
|
return true;
|
|
|
|
int cmpParentTypes = compareDependentTypes(parentType, shortestParentType);
|
|
if (cmpParentTypes != 0)
|
|
return cmpParentTypes < 0;
|
|
|
|
int cmpSubjectTypes = compareDependentTypes(subjectType, shortestSubjectType);
|
|
if (cmpSubjectTypes != 0)
|
|
return cmpSubjectTypes < 0;
|
|
|
|
int cmpParentProtos = TypeDecl::compare(parentProto, shortestParentProto);
|
|
return cmpParentProtos < 0;
|
|
};
|
|
|
|
auto recordShortestParentType = [&](Type parentType,
|
|
Type subjectType,
|
|
ProtocolDecl *parentProto) {
|
|
if (isShortestPath(parentType, subjectType, parentProto)) {
|
|
shortestParentType = parentType;
|
|
shortestSubjectType = subjectType;
|
|
shortestParentProto = parentProto;
|
|
}
|
|
};
|
|
|
|
for (auto constraint : conforms->second) {
|
|
auto *source = constraint.source;
|
|
|
|
switch (source->kind) {
|
|
case RequirementSource::Explicit:
|
|
case RequirementSource::Inferred:
|
|
// This is not a derived source, so it contributes nothing to the
|
|
// "shortest parent type" computation.
|
|
break;
|
|
|
|
case RequirementSource::ProtocolRequirement:
|
|
case RequirementSource::InferredProtocolRequirement: {
|
|
assert(source->parent->kind != RequirementSource::RequirementSignatureSelf);
|
|
|
|
// If we have a derived conformance requirement like T[.P].X : Q, we can
|
|
// recursively compute the conformance access path for T : P, and append
|
|
// the path element (Self.X : Q).
|
|
auto parentType = source->parent->getAffectedType()->getCanonicalType();
|
|
auto subjectType = source->getStoredType()->getCanonicalType();
|
|
auto *parentProto = source->getProtocolDecl();
|
|
|
|
// We might have multiple candidate parent types and protocols for the
|
|
// recursive step, so pick the shortest one.
|
|
recordShortestParentType(parentType, subjectType, parentProto);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// There should be no other way of testifying to a conformance on a
|
|
// dependent type.
|
|
llvm_unreachable("Bad requirement source for conformance on dependent type");
|
|
}
|
|
}
|
|
|
|
assert(shortestParentType);
|
|
|
|
SmallVector<ConformanceAccessPath::Entry, 2> path;
|
|
|
|
auto parentPath = getConformanceAccessPath(
|
|
shortestParentType, shortestParentProto);
|
|
for (auto entry : parentPath)
|
|
path.push_back(entry);
|
|
|
|
// Then, we add the subject type from the parent protocol's requirement
|
|
// signature.
|
|
path.emplace_back(shortestSubjectType, protocol);
|
|
|
|
ConformanceAccessPath result(builder.getASTContext().AllocateCopy(path));
|
|
equivClass->conformanceAccessPathCache.insert({protocol, result});
|
|
|
|
return result;
|
|
}
|
|
|
|
unsigned GenericParamKey::findIndexIn(
|
|
TypeArrayView<GenericTypeParamType> genericParams) const {
|
|
// For depth 0, we have random access. We perform the extra checking so that
|
|
// we can return
|
|
if (Depth == 0 && Index < genericParams.size() &&
|
|
genericParams[Index] == *this)
|
|
return Index;
|
|
|
|
// At other depths, perform a binary search.
|
|
unsigned result =
|
|
std::lower_bound(genericParams.begin(), genericParams.end(), *this,
|
|
Ordering())
|
|
- genericParams.begin();
|
|
if (result < genericParams.size() && genericParams[result] == *this)
|
|
return result;
|
|
|
|
// We didn't find the parameter we were looking for.
|
|
return genericParams.size();
|
|
}
|
|
|
|
SubstitutionMap GenericSignatureImpl::getIdentitySubstitutionMap() const {
|
|
return SubstitutionMap::get(const_cast<GenericSignatureImpl *>(this),
|
|
[](SubstitutableType *t) -> Type {
|
|
return Type(cast<GenericTypeParamType>(t));
|
|
},
|
|
MakeAbstractConformanceForGenericType());
|
|
}
|
|
|
|
GenericTypeParamType *GenericSignatureImpl::getSugaredType(
|
|
GenericTypeParamType *type) const {
|
|
unsigned ordinal = getGenericParamOrdinal(type);
|
|
return getGenericParams()[ordinal];
|
|
}
|
|
|
|
Type GenericSignatureImpl::getSugaredType(Type type) const {
|
|
if (!type->hasTypeParameter())
|
|
return type;
|
|
|
|
return type.transform([this](Type Ty) -> Type {
|
|
if (auto GP = dyn_cast<GenericTypeParamType>(Ty.getPointer())) {
|
|
return Type(getSugaredType(GP));
|
|
}
|
|
return Ty;
|
|
});
|
|
}
|
|
|
|
unsigned GenericSignatureImpl::getGenericParamOrdinal(
|
|
GenericTypeParamType *param) const {
|
|
return GenericParamKey(param).findIndexIn(getGenericParams());
|
|
}
|
|
|
|
bool GenericSignatureImpl::hasTypeVariable() const {
|
|
return GenericSignature::hasTypeVariable(getRequirements());
|
|
}
|
|
|
|
bool GenericSignature::hasTypeVariable(ArrayRef<Requirement> requirements) {
|
|
for (const auto &req : requirements) {
|
|
if (req.getFirstType()->hasTypeVariable())
|
|
return true;
|
|
|
|
switch (req.getKind()) {
|
|
case RequirementKind::Layout:
|
|
break;
|
|
|
|
case RequirementKind::Conformance:
|
|
case RequirementKind::SameType:
|
|
case RequirementKind::Superclass:
|
|
if (req.getSecondType()->hasTypeVariable())
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void GenericSignature::Profile(llvm::FoldingSetNodeID &id) const {
|
|
return GenericSignature::Profile(id, getPointer()->getGenericParams(),
|
|
getPointer()->getRequirements());
|
|
}
|
|
|
|
void GenericSignature::Profile(llvm::FoldingSetNodeID &ID,
|
|
TypeArrayView<GenericTypeParamType> genericParams,
|
|
ArrayRef<Requirement> requirements) {
|
|
return GenericSignatureImpl::Profile(ID, genericParams, requirements);
|
|
}
|
|
|
|
void swift::simple_display(raw_ostream &out, GenericSignature sig) {
|
|
if (sig)
|
|
sig->print(out);
|
|
else
|
|
out << "NULL";
|
|
}
|
|
|
|
bool Requirement::isCanonical() const {
|
|
if (getFirstType() && !getFirstType()->isCanonical())
|
|
return false;
|
|
|
|
switch (getKind()) {
|
|
case RequirementKind::Conformance:
|
|
case RequirementKind::SameType:
|
|
case RequirementKind::Superclass:
|
|
if (getSecondType() && !getSecondType()->isCanonical())
|
|
return false;
|
|
break;
|
|
|
|
case RequirementKind::Layout:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Get the canonical form of this requirement.
|
|
Requirement Requirement::getCanonical() const {
|
|
Type firstType = getFirstType();
|
|
if (firstType)
|
|
firstType = firstType->getCanonicalType();
|
|
|
|
switch (getKind()) {
|
|
case RequirementKind::Conformance:
|
|
case RequirementKind::SameType:
|
|
case RequirementKind::Superclass: {
|
|
Type secondType = getSecondType();
|
|
if (secondType)
|
|
secondType = secondType->getCanonicalType();
|
|
return Requirement(getKind(), firstType, secondType);
|
|
}
|
|
|
|
case RequirementKind::Layout:
|
|
return Requirement(getKind(), firstType, getLayoutConstraint());
|
|
}
|
|
llvm_unreachable("Unhandled RequirementKind in switch");
|
|
}
|
|
|
|
ProtocolDecl *Requirement::getProtocolDecl() const {
|
|
assert(getKind() == RequirementKind::Conformance);
|
|
return getSecondType()->castTo<ProtocolType>()->getDecl();
|
|
}
|