mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
AST: Split off ProtocolConformanceRef.cpp from ProtocolConformance.cpp
This commit is contained in:
@@ -74,6 +74,7 @@ add_swift_host_library(swiftAST STATIC
|
|||||||
PlatformKind.cpp
|
PlatformKind.cpp
|
||||||
PrettyStackTrace.cpp
|
PrettyStackTrace.cpp
|
||||||
ProtocolConformance.cpp
|
ProtocolConformance.cpp
|
||||||
|
ProtocolConformanceRef.cpp
|
||||||
RawComment.cpp
|
RawComment.cpp
|
||||||
RequirementEnvironment.cpp
|
RequirementEnvironment.cpp
|
||||||
RequirementMachine/ConcreteContraction.cpp
|
RequirementMachine/ConcreteContraction.cpp
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// This file implements the protocol conformance data structures.
|
// This file implements the ProtocolConformance class hierarchy.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
@@ -25,13 +25,9 @@
|
|||||||
#include "swift/AST/LazyResolver.h"
|
#include "swift/AST/LazyResolver.h"
|
||||||
#include "swift/AST/Module.h"
|
#include "swift/AST/Module.h"
|
||||||
#include "swift/AST/TypeCheckRequests.h"
|
#include "swift/AST/TypeCheckRequests.h"
|
||||||
#include "swift/AST/TypeWalker.h"
|
|
||||||
#include "swift/AST/Types.h"
|
#include "swift/AST/Types.h"
|
||||||
#include "swift/AST/TypeCheckRequests.h"
|
|
||||||
#include "swift/Basic/Statistic.h"
|
#include "swift/Basic/Statistic.h"
|
||||||
#include "llvm/ADT/MapVector.h"
|
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/TinyPtrVector.h"
|
|
||||||
#include "llvm/Support/PrettyStackTrace.h"
|
#include "llvm/Support/PrettyStackTrace.h"
|
||||||
#include "llvm/Support/SaveAndRestore.h"
|
#include "llvm/Support/SaveAndRestore.h"
|
||||||
|
|
||||||
@@ -79,128 +75,6 @@ void Witness::dump(llvm::raw_ostream &out) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolConformanceRef::ProtocolConformanceRef(ProtocolDecl *protocol,
|
|
||||||
ProtocolConformance *conf) {
|
|
||||||
assert(protocol != nullptr &&
|
|
||||||
"cannot construct ProtocolConformanceRef with null protocol");
|
|
||||||
if (conf) {
|
|
||||||
assert(protocol == conf->getProtocol() && "protocol conformance mismatch");
|
|
||||||
Union = conf;
|
|
||||||
} else {
|
|
||||||
Union = protocol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolDecl *ProtocolConformanceRef::getRequirement() const {
|
|
||||||
assert(!isInvalid());
|
|
||||||
|
|
||||||
if (isConcrete()) {
|
|
||||||
return getConcrete()->getProtocol();
|
|
||||||
} else {
|
|
||||||
return getAbstract();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolConformanceRef
|
|
||||||
ProtocolConformanceRef::subst(Type origType,
|
|
||||||
SubstitutionMap subMap,
|
|
||||||
SubstOptions options) const {
|
|
||||||
return subst(origType,
|
|
||||||
QuerySubstitutionMap{subMap},
|
|
||||||
LookUpConformanceInSubstitutionMap(subMap),
|
|
||||||
options);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolConformanceRef
|
|
||||||
ProtocolConformanceRef::subst(Type origType,
|
|
||||||
TypeSubstitutionFn subs,
|
|
||||||
LookupConformanceFn conformances,
|
|
||||||
SubstOptions options) const {
|
|
||||||
if (isInvalid())
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
// If we have a concrete conformance, we need to substitute the
|
|
||||||
// conformance to apply to the new type.
|
|
||||||
if (isConcrete())
|
|
||||||
return ProtocolConformanceRef(getConcrete()->subst(subs, conformances,
|
|
||||||
options));
|
|
||||||
// If the type is an opaque archetype, the conformance will remain abstract,
|
|
||||||
// unless we're specifically substituting opaque types.
|
|
||||||
if (auto origArchetype = origType->getAs<ArchetypeType>()) {
|
|
||||||
if (!options.contains(SubstFlags::SubstituteOpaqueArchetypes)
|
|
||||||
&& isa<OpaqueTypeArchetypeType>(origArchetype)) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, compute the substituted type.
|
|
||||||
auto substType = origType.subst(subs, conformances, options);
|
|
||||||
|
|
||||||
auto *proto = getRequirement();
|
|
||||||
|
|
||||||
// If the type is an existential, it must be self-conforming.
|
|
||||||
if (substType->isExistentialType()) {
|
|
||||||
auto optConformance =
|
|
||||||
proto->getModuleContext()->lookupExistentialConformance(substType,
|
|
||||||
proto);
|
|
||||||
if (optConformance)
|
|
||||||
return optConformance;
|
|
||||||
|
|
||||||
return ProtocolConformanceRef::forInvalid();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the conformance map.
|
|
||||||
return conformances(origType->getCanonicalType(), substType, proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() const {
|
|
||||||
if (!isConcrete())
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
auto *concrete = getConcrete()->subst(
|
|
||||||
[](SubstitutableType *type) -> Type {
|
|
||||||
if (auto *archetypeType = type->getAs<ArchetypeType>())
|
|
||||||
return archetypeType->getInterfaceType();
|
|
||||||
return type;
|
|
||||||
},
|
|
||||||
MakeAbstractConformanceForGenericType());
|
|
||||||
return ProtocolConformanceRef(concrete);
|
|
||||||
}
|
|
||||||
|
|
||||||
Type
|
|
||||||
ProtocolConformanceRef::getTypeWitnessByName(Type type, Identifier name) const {
|
|
||||||
assert(!isInvalid());
|
|
||||||
|
|
||||||
// Find the named requirement.
|
|
||||||
ProtocolDecl *proto = getRequirement();
|
|
||||||
auto *assocType = proto->getAssociatedType(name);
|
|
||||||
|
|
||||||
// FIXME: Shouldn't this be a hard error?
|
|
||||||
if (!assocType)
|
|
||||||
return ErrorType::get(proto->getASTContext());
|
|
||||||
|
|
||||||
return assocType->getDeclaredInterfaceType().subst(
|
|
||||||
SubstitutionMap::getProtocolSubstitutions(proto, type, *this));
|
|
||||||
}
|
|
||||||
|
|
||||||
ConcreteDeclRef
|
|
||||||
ProtocolConformanceRef::getWitnessByName(Type type, DeclName name) const {
|
|
||||||
// Find the named requirement.
|
|
||||||
auto *proto = getRequirement();
|
|
||||||
auto *requirement = proto->getSingleRequirement(name);
|
|
||||||
if (requirement == nullptr)
|
|
||||||
return ConcreteDeclRef();
|
|
||||||
|
|
||||||
// For a type with dependent conformance, just return the requirement from
|
|
||||||
// the protocol. There are no protocol conformance tables.
|
|
||||||
if (!isConcrete()) {
|
|
||||||
auto subs = SubstitutionMap::getProtocolSubstitutions(proto, type, *this);
|
|
||||||
return ConcreteDeclRef(requirement, subs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getConcrete()->getWitnessDeclRef(requirement);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CONFORMANCE_SUBCLASS_DISPATCH(Method, Args) \
|
#define CONFORMANCE_SUBCLASS_DISPATCH(Method, Args) \
|
||||||
switch (getKind()) { \
|
switch (getKind()) { \
|
||||||
case ProtocolConformanceKind::Normal: \
|
case ProtocolConformanceKind::Normal: \
|
||||||
@@ -455,26 +329,6 @@ ArrayRef<Requirement> ProtocolConformance::getConditionalRequirements() const {
|
|||||||
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirements, ());
|
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirements, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<ArrayRef<Requirement>>
|
|
||||||
ProtocolConformanceRef::getConditionalRequirementsIfAvailable() const {
|
|
||||||
if (isConcrete())
|
|
||||||
return getConcrete()->getConditionalRequirementsIfAvailable();
|
|
||||||
else
|
|
||||||
// An abstract conformance is never conditional: any conditionality in the
|
|
||||||
// concrete types that will eventually pass through this at runtime is
|
|
||||||
// completely pre-checked and packaged up.
|
|
||||||
return ArrayRef<Requirement>();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayRef<Requirement>
|
|
||||||
ProtocolConformanceRef::getConditionalRequirements() const {
|
|
||||||
if (isConcrete())
|
|
||||||
return getConcrete()->getConditionalRequirements();
|
|
||||||
else
|
|
||||||
// An abstract conformance is never conditional, as above.
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<ArrayRef<Requirement>>
|
Optional<ArrayRef<Requirement>>
|
||||||
NormalProtocolConformance::getConditionalRequirementsIfAvailable() const {
|
NormalProtocolConformance::getConditionalRequirementsIfAvailable() const {
|
||||||
const auto &eval = getDeclContext()->getASTContext().evaluator;
|
const auto &eval = getDeclContext()->getASTContext().evaluator;
|
||||||
@@ -682,54 +536,6 @@ Type ProtocolConformance::getAssociatedType(Type assocType) const {
|
|||||||
return ref.getAssociatedType(getType(), assocType);
|
return ref.getAssociatedType(getType(), assocType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type ProtocolConformanceRef::getAssociatedType(Type conformingType,
|
|
||||||
Type assocType) const {
|
|
||||||
assert(!isConcrete() || getConcrete()->getType()->isEqual(conformingType));
|
|
||||||
|
|
||||||
auto type = assocType->getCanonicalType();
|
|
||||||
auto proto = getRequirement();
|
|
||||||
|
|
||||||
// Fast path for generic parameters.
|
|
||||||
if (isa<GenericTypeParamType>(type)) {
|
|
||||||
assert(type->isEqual(proto->getSelfInterfaceType()) &&
|
|
||||||
"type parameter in protocol was not Self");
|
|
||||||
return conformingType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fast path for dependent member types on 'Self' of our associated types.
|
|
||||||
auto memberType = cast<DependentMemberType>(type);
|
|
||||||
if (memberType.getBase()->isEqual(proto->getSelfInterfaceType()) &&
|
|
||||||
memberType->getAssocType()->getProtocol() == proto &&
|
|
||||||
isConcrete())
|
|
||||||
return getConcrete()->getTypeWitness(memberType->getAssocType());
|
|
||||||
|
|
||||||
// General case: consult the substitution map.
|
|
||||||
auto substMap =
|
|
||||||
SubstitutionMap::getProtocolSubstitutions(proto, conformingType, *this);
|
|
||||||
return type.subst(substMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolConformanceRef
|
|
||||||
ProtocolConformanceRef::getAssociatedConformance(Type conformingType,
|
|
||||||
Type assocType,
|
|
||||||
ProtocolDecl *protocol) const {
|
|
||||||
// If this is a concrete conformance, look up the associated conformance.
|
|
||||||
if (isConcrete()) {
|
|
||||||
auto conformance = getConcrete();
|
|
||||||
assert(conformance->getType()->isEqual(conformingType));
|
|
||||||
return conformance->getAssociatedConformance(assocType, protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, apply the substitution {self -> conformingType}
|
|
||||||
// to the abstract conformance requirement laid upon the dependent type
|
|
||||||
// by the protocol.
|
|
||||||
auto subMap =
|
|
||||||
SubstitutionMap::getProtocolSubstitutions(getRequirement(),
|
|
||||||
conformingType, *this);
|
|
||||||
auto abstractConf = ProtocolConformanceRef(protocol);
|
|
||||||
return abstractConf.subst(assocType, subMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolConformanceRef
|
ProtocolConformanceRef
|
||||||
ProtocolConformance::getAssociatedConformance(Type assocType,
|
ProtocolConformance::getAssociatedConformance(Type assocType,
|
||||||
ProtocolDecl *protocol) const {
|
ProtocolDecl *protocol) const {
|
||||||
@@ -1669,20 +1475,6 @@ ProtocolConformance *ProtocolConformance::getCanonicalConformance() {
|
|||||||
llvm_unreachable("bad ProtocolConformanceKind");
|
llvm_unreachable("bad ProtocolConformanceKind");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check of all types used by the conformance are canonical.
|
|
||||||
bool ProtocolConformanceRef::isCanonical() const {
|
|
||||||
if (isAbstract() || isInvalid())
|
|
||||||
return true;
|
|
||||||
return getConcrete()->isCanonical();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolConformanceRef
|
|
||||||
ProtocolConformanceRef::getCanonicalConformanceRef() const {
|
|
||||||
if (isAbstract() || isInvalid())
|
|
||||||
return *this;
|
|
||||||
return ProtocolConformanceRef(getConcrete()->getCanonicalConformance());
|
|
||||||
}
|
|
||||||
|
|
||||||
BuiltinProtocolConformance::BuiltinProtocolConformance(
|
BuiltinProtocolConformance::BuiltinProtocolConformance(
|
||||||
Type conformingType, ProtocolDecl *protocol,
|
Type conformingType, ProtocolDecl *protocol,
|
||||||
GenericSignature genericSig,
|
GenericSignature genericSig,
|
||||||
@@ -1742,76 +1534,3 @@ void swift::simple_display(llvm::raw_ostream &out,
|
|||||||
SourceLoc swift::extractNearestSourceLoc(const ProtocolConformance *conformance) {
|
SourceLoc swift::extractNearestSourceLoc(const ProtocolConformance *conformance) {
|
||||||
return extractNearestSourceLoc(conformance->getDeclContext());
|
return extractNearestSourceLoc(conformance->getDeclContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
void swift::simple_display(llvm::raw_ostream &out, ProtocolConformanceRef conformanceRef) {
|
|
||||||
if (conformanceRef.isAbstract()) {
|
|
||||||
simple_display(out, conformanceRef.getAbstract());
|
|
||||||
} else if (conformanceRef.isConcrete()) {
|
|
||||||
simple_display(out, conformanceRef.getConcrete());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLoc swift::extractNearestSourceLoc(const ProtocolConformanceRef conformanceRef) {
|
|
||||||
if (conformanceRef.isAbstract()) {
|
|
||||||
return extractNearestSourceLoc(conformanceRef.getAbstract());
|
|
||||||
} else if (conformanceRef.isConcrete()) {
|
|
||||||
return extractNearestSourceLoc(conformanceRef.getConcrete());
|
|
||||||
}
|
|
||||||
return SourceLoc();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProtocolConformanceRef::hasUnavailableConformance() const {
|
|
||||||
if (isInvalid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Abstract conformances are never unavailable.
|
|
||||||
if (!isConcrete())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check whether this conformance is on an unavailable extension.
|
|
||||||
auto concrete = getConcrete();
|
|
||||||
auto ext = dyn_cast<ExtensionDecl>(concrete->getDeclContext());
|
|
||||||
if (ext && AvailableAttr::isUnavailable(ext))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Check the conformances in the substitution map.
|
|
||||||
auto module = concrete->getDeclContext()->getParentModule();
|
|
||||||
auto subMap = concrete->getSubstitutions(module);
|
|
||||||
for (auto subConformance : subMap.getConformances()) {
|
|
||||||
if (subConformance.hasUnavailableConformance())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProtocolConformanceRef::hasMissingConformance(ModuleDecl *module) const {
|
|
||||||
return forEachMissingConformance(module,
|
|
||||||
[](BuiltinProtocolConformance *builtin) {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProtocolConformanceRef::forEachMissingConformance(
|
|
||||||
ModuleDecl *module,
|
|
||||||
llvm::function_ref<bool(BuiltinProtocolConformance *missing)> fn) const {
|
|
||||||
if (!isConcrete())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Is this a missing conformance?
|
|
||||||
ProtocolConformance *concreteConf = getConcrete();
|
|
||||||
RootProtocolConformance *rootConf = concreteConf->getRootConformance();
|
|
||||||
if (auto builtinConformance = dyn_cast<BuiltinProtocolConformance>(rootConf)){
|
|
||||||
if (builtinConformance->isMissing() && fn(builtinConformance))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check conformances that are part of this conformance.
|
|
||||||
auto subMap = concreteConf->getSubstitutions(module);
|
|
||||||
for (auto conformance : subMap.getConformances()) {
|
|
||||||
if (conformance.forEachMissingConformance(module, fn))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
305
lib/AST/ProtocolConformanceRef.cpp
Normal file
305
lib/AST/ProtocolConformanceRef.cpp
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
//===--- ProtocolConformance.cpp - AST Protocol Conformance Reference -----===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 - 2022 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 ProtocolConformanceRef structure, which wraps a
|
||||||
|
// concrete or abstract conformance, or is invalid.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "swift/AST/ProtocolConformanceRef.h"
|
||||||
|
#include "swift/AST/ASTContext.h"
|
||||||
|
#include "swift/AST/Availability.h"
|
||||||
|
#include "swift/AST/Decl.h"
|
||||||
|
#include "swift/AST/Module.h"
|
||||||
|
#include "swift/AST/TypeCheckRequests.h"
|
||||||
|
#include "swift/AST/Types.h"
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "AST"
|
||||||
|
|
||||||
|
using namespace swift;
|
||||||
|
|
||||||
|
ProtocolConformanceRef::ProtocolConformanceRef(ProtocolDecl *protocol,
|
||||||
|
ProtocolConformance *conf) {
|
||||||
|
assert(protocol != nullptr &&
|
||||||
|
"cannot construct ProtocolConformanceRef with null protocol");
|
||||||
|
if (conf) {
|
||||||
|
assert(protocol == conf->getProtocol() && "protocol conformance mismatch");
|
||||||
|
Union = conf;
|
||||||
|
} else {
|
||||||
|
Union = protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolDecl *ProtocolConformanceRef::getRequirement() const {
|
||||||
|
assert(!isInvalid());
|
||||||
|
|
||||||
|
if (isConcrete()) {
|
||||||
|
return getConcrete()->getProtocol();
|
||||||
|
} else {
|
||||||
|
return getAbstract();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolConformanceRef
|
||||||
|
ProtocolConformanceRef::subst(Type origType,
|
||||||
|
SubstitutionMap subMap,
|
||||||
|
SubstOptions options) const {
|
||||||
|
return subst(origType,
|
||||||
|
QuerySubstitutionMap{subMap},
|
||||||
|
LookUpConformanceInSubstitutionMap(subMap),
|
||||||
|
options);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolConformanceRef
|
||||||
|
ProtocolConformanceRef::subst(Type origType,
|
||||||
|
TypeSubstitutionFn subs,
|
||||||
|
LookupConformanceFn conformances,
|
||||||
|
SubstOptions options) const {
|
||||||
|
if (isInvalid())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
// If we have a concrete conformance, we need to substitute the
|
||||||
|
// conformance to apply to the new type.
|
||||||
|
if (isConcrete())
|
||||||
|
return ProtocolConformanceRef(getConcrete()->subst(subs, conformances,
|
||||||
|
options));
|
||||||
|
// If the type is an opaque archetype, the conformance will remain abstract,
|
||||||
|
// unless we're specifically substituting opaque types.
|
||||||
|
if (auto origArchetype = origType->getAs<ArchetypeType>()) {
|
||||||
|
if (!options.contains(SubstFlags::SubstituteOpaqueArchetypes)
|
||||||
|
&& isa<OpaqueTypeArchetypeType>(origArchetype)) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, compute the substituted type.
|
||||||
|
auto substType = origType.subst(subs, conformances, options);
|
||||||
|
|
||||||
|
auto *proto = getRequirement();
|
||||||
|
|
||||||
|
// If the type is an existential, it must be self-conforming.
|
||||||
|
if (substType->isExistentialType()) {
|
||||||
|
auto optConformance =
|
||||||
|
proto->getModuleContext()->lookupExistentialConformance(substType,
|
||||||
|
proto);
|
||||||
|
if (optConformance)
|
||||||
|
return optConformance;
|
||||||
|
|
||||||
|
return ProtocolConformanceRef::forInvalid();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the conformance map.
|
||||||
|
return conformances(origType->getCanonicalType(), substType, proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() const {
|
||||||
|
if (!isConcrete())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
auto *concrete = getConcrete()->subst(
|
||||||
|
[](SubstitutableType *type) -> Type {
|
||||||
|
if (auto *archetypeType = type->getAs<ArchetypeType>())
|
||||||
|
return archetypeType->getInterfaceType();
|
||||||
|
return type;
|
||||||
|
},
|
||||||
|
MakeAbstractConformanceForGenericType());
|
||||||
|
return ProtocolConformanceRef(concrete);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type
|
||||||
|
ProtocolConformanceRef::getTypeWitnessByName(Type type, Identifier name) const {
|
||||||
|
assert(!isInvalid());
|
||||||
|
|
||||||
|
// Find the named requirement.
|
||||||
|
ProtocolDecl *proto = getRequirement();
|
||||||
|
auto *assocType = proto->getAssociatedType(name);
|
||||||
|
|
||||||
|
// FIXME: Shouldn't this be a hard error?
|
||||||
|
if (!assocType)
|
||||||
|
return ErrorType::get(proto->getASTContext());
|
||||||
|
|
||||||
|
return assocType->getDeclaredInterfaceType().subst(
|
||||||
|
SubstitutionMap::getProtocolSubstitutions(proto, type, *this));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcreteDeclRef
|
||||||
|
ProtocolConformanceRef::getWitnessByName(Type type, DeclName name) const {
|
||||||
|
// Find the named requirement.
|
||||||
|
auto *proto = getRequirement();
|
||||||
|
auto *requirement = proto->getSingleRequirement(name);
|
||||||
|
if (requirement == nullptr)
|
||||||
|
return ConcreteDeclRef();
|
||||||
|
|
||||||
|
// For a type with dependent conformance, just return the requirement from
|
||||||
|
// the protocol. There are no protocol conformance tables.
|
||||||
|
if (!isConcrete()) {
|
||||||
|
auto subs = SubstitutionMap::getProtocolSubstitutions(proto, type, *this);
|
||||||
|
return ConcreteDeclRef(requirement, subs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getConcrete()->getWitnessDeclRef(requirement);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ArrayRef<Requirement>>
|
||||||
|
ProtocolConformanceRef::getConditionalRequirementsIfAvailable() const {
|
||||||
|
if (isConcrete())
|
||||||
|
return getConcrete()->getConditionalRequirementsIfAvailable();
|
||||||
|
else
|
||||||
|
// An abstract conformance is never conditional: any conditionality in the
|
||||||
|
// concrete types that will eventually pass through this at runtime is
|
||||||
|
// completely pre-checked and packaged up.
|
||||||
|
return ArrayRef<Requirement>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayRef<Requirement>
|
||||||
|
ProtocolConformanceRef::getConditionalRequirements() const {
|
||||||
|
if (isConcrete())
|
||||||
|
return getConcrete()->getConditionalRequirements();
|
||||||
|
else
|
||||||
|
// An abstract conformance is never conditional, as above.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Type ProtocolConformanceRef::getAssociatedType(Type conformingType,
|
||||||
|
Type assocType) const {
|
||||||
|
assert(!isConcrete() || getConcrete()->getType()->isEqual(conformingType));
|
||||||
|
|
||||||
|
auto type = assocType->getCanonicalType();
|
||||||
|
auto proto = getRequirement();
|
||||||
|
|
||||||
|
// Fast path for generic parameters.
|
||||||
|
if (isa<GenericTypeParamType>(type)) {
|
||||||
|
assert(type->isEqual(proto->getSelfInterfaceType()) &&
|
||||||
|
"type parameter in protocol was not Self");
|
||||||
|
return conformingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast path for dependent member types on 'Self' of our associated types.
|
||||||
|
auto memberType = cast<DependentMemberType>(type);
|
||||||
|
if (memberType.getBase()->isEqual(proto->getSelfInterfaceType()) &&
|
||||||
|
memberType->getAssocType()->getProtocol() == proto &&
|
||||||
|
isConcrete())
|
||||||
|
return getConcrete()->getTypeWitness(memberType->getAssocType());
|
||||||
|
|
||||||
|
// General case: consult the substitution map.
|
||||||
|
auto substMap =
|
||||||
|
SubstitutionMap::getProtocolSubstitutions(proto, conformingType, *this);
|
||||||
|
return type.subst(substMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolConformanceRef
|
||||||
|
ProtocolConformanceRef::getAssociatedConformance(Type conformingType,
|
||||||
|
Type assocType,
|
||||||
|
ProtocolDecl *protocol) const {
|
||||||
|
// If this is a concrete conformance, look up the associated conformance.
|
||||||
|
if (isConcrete()) {
|
||||||
|
auto conformance = getConcrete();
|
||||||
|
assert(conformance->getType()->isEqual(conformingType));
|
||||||
|
return conformance->getAssociatedConformance(assocType, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, apply the substitution {self -> conformingType}
|
||||||
|
// to the abstract conformance requirement laid upon the dependent type
|
||||||
|
// by the protocol.
|
||||||
|
auto subMap =
|
||||||
|
SubstitutionMap::getProtocolSubstitutions(getRequirement(),
|
||||||
|
conformingType, *this);
|
||||||
|
auto abstractConf = ProtocolConformanceRef(protocol);
|
||||||
|
return abstractConf.subst(assocType, subMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check of all types used by the conformance are canonical.
|
||||||
|
bool ProtocolConformanceRef::isCanonical() const {
|
||||||
|
if (isAbstract() || isInvalid())
|
||||||
|
return true;
|
||||||
|
return getConcrete()->isCanonical();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolConformanceRef
|
||||||
|
ProtocolConformanceRef::getCanonicalConformanceRef() const {
|
||||||
|
if (isAbstract() || isInvalid())
|
||||||
|
return *this;
|
||||||
|
return ProtocolConformanceRef(getConcrete()->getCanonicalConformance());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProtocolConformanceRef::hasUnavailableConformance() const {
|
||||||
|
if (isInvalid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Abstract conformances are never unavailable.
|
||||||
|
if (!isConcrete())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check whether this conformance is on an unavailable extension.
|
||||||
|
auto concrete = getConcrete();
|
||||||
|
auto ext = dyn_cast<ExtensionDecl>(concrete->getDeclContext());
|
||||||
|
if (ext && AvailableAttr::isUnavailable(ext))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Check the conformances in the substitution map.
|
||||||
|
auto module = concrete->getDeclContext()->getParentModule();
|
||||||
|
auto subMap = concrete->getSubstitutions(module);
|
||||||
|
for (auto subConformance : subMap.getConformances()) {
|
||||||
|
if (subConformance.hasUnavailableConformance())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProtocolConformanceRef::hasMissingConformance(ModuleDecl *module) const {
|
||||||
|
return forEachMissingConformance(module,
|
||||||
|
[](BuiltinProtocolConformance *builtin) {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProtocolConformanceRef::forEachMissingConformance(
|
||||||
|
ModuleDecl *module,
|
||||||
|
llvm::function_ref<bool(BuiltinProtocolConformance *missing)> fn) const {
|
||||||
|
if (!isConcrete())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Is this a missing conformance?
|
||||||
|
ProtocolConformance *concreteConf = getConcrete();
|
||||||
|
RootProtocolConformance *rootConf = concreteConf->getRootConformance();
|
||||||
|
if (auto builtinConformance = dyn_cast<BuiltinProtocolConformance>(rootConf)){
|
||||||
|
if (builtinConformance->isMissing() && fn(builtinConformance))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check conformances that are part of this conformance.
|
||||||
|
auto subMap = concreteConf->getSubstitutions(module);
|
||||||
|
for (auto conformance : subMap.getConformances()) {
|
||||||
|
if (conformance.forEachMissingConformance(module, fn))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swift::simple_display(llvm::raw_ostream &out, ProtocolConformanceRef conformanceRef) {
|
||||||
|
if (conformanceRef.isAbstract()) {
|
||||||
|
simple_display(out, conformanceRef.getAbstract());
|
||||||
|
} else if (conformanceRef.isConcrete()) {
|
||||||
|
simple_display(out, conformanceRef.getConcrete());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLoc swift::extractNearestSourceLoc(const ProtocolConformanceRef conformanceRef) {
|
||||||
|
if (conformanceRef.isAbstract()) {
|
||||||
|
return extractNearestSourceLoc(conformanceRef.getAbstract());
|
||||||
|
} else if (conformanceRef.isConcrete()) {
|
||||||
|
return extractNearestSourceLoc(conformanceRef.getConcrete());
|
||||||
|
}
|
||||||
|
return SourceLoc();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user