mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[AST] Compute conditional requirements in a conformance.
This allows determining which requirements make a conformance conditional; as in, which requirements aren't known as part of the type itself. Additionally, use this to assert that a few builtin protocols aren't conditionally-conformed-to, something we won't support for now.
This commit is contained in:
@@ -296,6 +296,12 @@ public:
|
|||||||
/// The type parameters must be known to not be concrete within the context.
|
/// The type parameters must be known to not be concrete within the context.
|
||||||
bool areSameTypeParameterInContext(Type type1, Type type2);
|
bool areSameTypeParameterInContext(Type type1, Type type2);
|
||||||
|
|
||||||
|
/// Determine if \c sig can prove \c requirement, meaning that it can deduce
|
||||||
|
/// T: Foo or T == U (etc.) with the information it knows. This includes
|
||||||
|
/// checking against global state, if any/all of the types in the requirement
|
||||||
|
/// are concrete, not type parameters.
|
||||||
|
bool isRequirementSatisfied(Requirement requirement);
|
||||||
|
|
||||||
/// Return the canonical version of the given type under this generic
|
/// Return the canonical version of the given type under this generic
|
||||||
/// signature.
|
/// signature.
|
||||||
CanType getCanonicalTypeInContext(Type type);
|
CanType getCanonicalTypeInContext(Type type);
|
||||||
|
|||||||
@@ -294,6 +294,10 @@ public:
|
|||||||
/// Get the property declaration for a behavior conformance, if this is one.
|
/// Get the property declaration for a behavior conformance, if this is one.
|
||||||
AbstractStorageDecl *getBehaviorDecl() const;
|
AbstractStorageDecl *getBehaviorDecl() const;
|
||||||
|
|
||||||
|
/// Get any additional requirements that are required for this conformance to
|
||||||
|
/// be satisfied.
|
||||||
|
ArrayRef<Requirement> getConditionalRequirements() const;
|
||||||
|
|
||||||
/// Substitute the conforming type and produce a ProtocolConformance that
|
/// Substitute the conforming type and produce a ProtocolConformance that
|
||||||
/// applies to the substituted type.
|
/// applies to the substituted type.
|
||||||
ProtocolConformance *subst(Type substType,
|
ProtocolConformance *subst(Type substType,
|
||||||
@@ -349,6 +353,10 @@ class NormalProtocolConformance : public ProtocolConformance,
|
|||||||
/// requirement signature of the protocol.
|
/// requirement signature of the protocol.
|
||||||
ArrayRef<ProtocolConformanceRef> SignatureConformances;
|
ArrayRef<ProtocolConformanceRef> SignatureConformances;
|
||||||
|
|
||||||
|
/// Any additional requirements that are required for this conformance to
|
||||||
|
/// apply, e.g. 'Something: Baz' in 'extension Foo: Bar where Something: Baz'.
|
||||||
|
ArrayRef<Requirement> ConditionalRequirements;
|
||||||
|
|
||||||
/// The lazy member loader provides callbacks for populating imported and
|
/// The lazy member loader provides callbacks for populating imported and
|
||||||
/// deserialized conformances.
|
/// deserialized conformances.
|
||||||
///
|
///
|
||||||
@@ -365,6 +373,7 @@ class NormalProtocolConformance : public ProtocolConformance,
|
|||||||
: ProtocolConformance(ProtocolConformanceKind::Normal, conformingType),
|
: ProtocolConformance(ProtocolConformanceKind::Normal, conformingType),
|
||||||
ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(dc, false)
|
ProtocolAndState(protocol, state), Loc(loc), ContextAndInvalid(dc, false)
|
||||||
{
|
{
|
||||||
|
differenceAndStoreConditionalRequirements();
|
||||||
}
|
}
|
||||||
|
|
||||||
NormalProtocolConformance(Type conformingType,
|
NormalProtocolConformance(Type conformingType,
|
||||||
@@ -375,10 +384,13 @@ class NormalProtocolConformance : public ProtocolConformance,
|
|||||||
ProtocolAndState(protocol, state), Loc(loc),
|
ProtocolAndState(protocol, state), Loc(loc),
|
||||||
ContextAndInvalid(behaviorStorage, false)
|
ContextAndInvalid(behaviorStorage, false)
|
||||||
{
|
{
|
||||||
|
differenceAndStoreConditionalRequirements();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolveLazyInfo() const;
|
void resolveLazyInfo() const;
|
||||||
|
|
||||||
|
void differenceAndStoreConditionalRequirements();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Get the protocol being conformed to.
|
/// Get the protocol being conformed to.
|
||||||
ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); }
|
ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); }
|
||||||
@@ -397,6 +409,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get any additional requirements that are required for this conformance to
|
||||||
|
/// be satisfied, e.g. for Array<T>: Equatable, T: Equatable also needs
|
||||||
|
/// to be satisfied.
|
||||||
|
ArrayRef<Requirement> getConditionalRequirements() const {
|
||||||
|
return ConditionalRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve the state of this conformance.
|
/// Retrieve the state of this conformance.
|
||||||
ProtocolConformanceState getState() const {
|
ProtocolConformanceState getState() const {
|
||||||
return ProtocolAndState.getInt();
|
return ProtocolAndState.getInt();
|
||||||
@@ -580,6 +599,10 @@ class SpecializedProtocolConformance : public ProtocolConformance,
|
|||||||
/// generic conformance.
|
/// generic conformance.
|
||||||
mutable TypeWitnessMap TypeWitnesses;
|
mutable TypeWitnessMap TypeWitnesses;
|
||||||
|
|
||||||
|
/// Any conditional requirements, in substituted form. (E.g. given Foo<T>: Bar
|
||||||
|
/// where T: Bar, Foo<Baz<U>> will include Baz<U>: Bar.)
|
||||||
|
ArrayRef<Requirement> ConditionalRequirements;
|
||||||
|
|
||||||
friend class ASTContext;
|
friend class ASTContext;
|
||||||
|
|
||||||
SpecializedProtocolConformance(Type conformingType,
|
SpecializedProtocolConformance(Type conformingType,
|
||||||
@@ -599,6 +622,15 @@ public:
|
|||||||
return GenericSubstitutions;
|
return GenericSubstitutions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the substitution map representing the substitutions used to produce
|
||||||
|
/// this specialized conformance.
|
||||||
|
SubstitutionMap getSubstitutionMap() const;
|
||||||
|
|
||||||
|
/// Get any requirements that must be satisfied for this conformance to apply.
|
||||||
|
ArrayRef<Requirement> getConditionalRequirements() const {
|
||||||
|
return ConditionalRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the protocol being conformed to.
|
/// Get the protocol being conformed to.
|
||||||
ProtocolDecl *getProtocol() const {
|
ProtocolDecl *getProtocol() const {
|
||||||
return GenericConformance->getProtocol();
|
return GenericConformance->getProtocol();
|
||||||
@@ -697,6 +729,11 @@ public:
|
|||||||
return InheritedConformance->getProtocol();
|
return InheritedConformance->getProtocol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get any requirements that must be satisfied for this conformance to apply.
|
||||||
|
ArrayRef<Requirement> getConditionalRequirements() const {
|
||||||
|
return InheritedConformance->getConditionalRequirements();
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the declaration context that contains the conforming extension or
|
/// Get the declaration context that contains the conforming extension or
|
||||||
/// nominal type declaration.
|
/// nominal type declaration.
|
||||||
DeclContext *getDeclContext() const {
|
DeclContext *getDeclContext() const {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/Hashing.h"
|
#include "llvm/ADT/Hashing.h"
|
||||||
#include "llvm/ADT/PointerUnion.h"
|
#include "llvm/ADT/PointerUnion.h"
|
||||||
|
#include "swift/AST/Requirement.h"
|
||||||
#include "swift/AST/TypeAlignments.h"
|
#include "swift/AST/TypeAlignments.h"
|
||||||
#include "swift/AST/Type.h"
|
#include "swift/AST/Type.h"
|
||||||
|
|
||||||
@@ -128,6 +129,10 @@ public:
|
|||||||
|
|
||||||
/// Create a canonical conformance from the current one.
|
/// Create a canonical conformance from the current one.
|
||||||
ProtocolConformanceRef getCanonicalConformanceRef() const;
|
ProtocolConformanceRef getCanonicalConformanceRef() const;
|
||||||
|
|
||||||
|
/// Get any additional requirements that are required for this conformance to
|
||||||
|
/// be satisfied.
|
||||||
|
ArrayRef<Requirement> getConditionalRequirements() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|||||||
@@ -633,6 +633,63 @@ bool GenericSignature::areSameTypeParameterInContext(Type type1, Type type2) {
|
|||||||
return equivClass1 == equivClass2;
|
return equivClass1 == equivClass2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GenericSignature::isRequirementSatisfied(Requirement requirement) {
|
||||||
|
auto GSB = getGenericSignatureBuilder();
|
||||||
|
|
||||||
|
auto firstType = requirement.getFirstType();
|
||||||
|
auto canFirstType = getCanonicalTypeInContext(firstType);
|
||||||
|
|
||||||
|
switch (requirement.getKind()) {
|
||||||
|
case RequirementKind::Conformance: {
|
||||||
|
auto protocolType = requirement.getSecondType()->castTo<ProtocolType>();
|
||||||
|
auto protocol = protocolType->getDecl();
|
||||||
|
|
||||||
|
if (canFirstType->isTypeParameter())
|
||||||
|
return conformsToProtocol(canFirstType, protocol);
|
||||||
|
else
|
||||||
|
return (bool)GSB->lookupConformance(/*dependentType=*/CanType(),
|
||||||
|
canFirstType, protocolType);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (canFirstType->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())
|
||||||
|
return getLayoutConstraint(canFirstType) == requiredLayout;
|
||||||
|
else {
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool GenericSignature::isCanonicalTypeInContext(Type type) {
|
bool GenericSignature::isCanonicalTypeInContext(Type type) {
|
||||||
// If the type isn't independently canonical, it's certainly not canonical
|
// If the type isn't independently canonical, it's certainly not canonical
|
||||||
// in this context.
|
// in this context.
|
||||||
|
|||||||
@@ -285,6 +285,63 @@ AbstractStorageDecl *ProtocolConformance::getBehaviorDecl() const {
|
|||||||
return getRootNormalConformance()->getBehaviorDecl();
|
return getRootNormalConformance()->getBehaviorDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayRef<Requirement> ProtocolConformance::getConditionalRequirements() const {
|
||||||
|
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirements, ());
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayRef<Requirement>
|
||||||
|
ProtocolConformanceRef::getConditionalRequirements() const {
|
||||||
|
if (isConcrete())
|
||||||
|
return getConcrete()->getConditionalRequirements();
|
||||||
|
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 {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalProtocolConformance::differenceAndStoreConditionalRequirements() {
|
||||||
|
assert(ConditionalRequirements.size() == 0 &&
|
||||||
|
"should not recompute conditional requirements");
|
||||||
|
auto &ctxt = getProtocol()->getASTContext();
|
||||||
|
auto DC = getDeclContext();
|
||||||
|
// Only conformances in extensions can be conditional
|
||||||
|
if (!isa<ExtensionDecl>(DC))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto typeSig = DC->getAsNominalTypeOrNominalTypeExtensionContext()
|
||||||
|
->getGenericSignature();
|
||||||
|
auto extensionSig = DC->getGenericSignatureOfContext();
|
||||||
|
|
||||||
|
// If the type is generic, the extension should be too, and vice versa.
|
||||||
|
assert((bool)typeSig == (bool)extensionSig &&
|
||||||
|
"unexpected generic-ness mismatch on conformance");
|
||||||
|
if (!typeSig)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto canExtensionSig = extensionSig->getCanonicalSignature();
|
||||||
|
auto canTypeSig = typeSig->getCanonicalSignature();
|
||||||
|
if (canTypeSig == canExtensionSig)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The extension signature should be a superset of the type signature, meaning
|
||||||
|
// every thing in the type signature either is included too or is implied by
|
||||||
|
// something else. The most important bit is having the same type
|
||||||
|
// parameters. (NB. if/when Swift gets parameterized extensions, this needs to
|
||||||
|
// change.)
|
||||||
|
assert(canTypeSig.getGenericParams() == canExtensionSig.getGenericParams());
|
||||||
|
|
||||||
|
auto mod = DC->getParentModule();
|
||||||
|
// Find the requirements in the extension that aren't proved by the original
|
||||||
|
// type, these are the ones that make the conformance conditional.
|
||||||
|
SmallVector<Requirement, 4> reqs;
|
||||||
|
for (auto requirement : canExtensionSig->getRequirements()) {
|
||||||
|
if (!canTypeSig->isRequirementSatisfied(requirement))
|
||||||
|
reqs.push_back(requirement);
|
||||||
|
}
|
||||||
|
ConditionalRequirements = ctxt.AllocateCopy(reqs);
|
||||||
|
}
|
||||||
|
|
||||||
void NormalProtocolConformance::setSignatureConformances(
|
void NormalProtocolConformance::setSignatureConformances(
|
||||||
ArrayRef<ProtocolConformanceRef> conformances) {
|
ArrayRef<ProtocolConformanceRef> conformances) {
|
||||||
auto &ctx = getProtocol()->getASTContext();
|
auto &ctx = getProtocol()->getASTContext();
|
||||||
@@ -635,11 +692,24 @@ SpecializedProtocolConformance::SpecializedProtocolConformance(
|
|||||||
GenericSubstitutions(substitutions)
|
GenericSubstitutions(substitutions)
|
||||||
{
|
{
|
||||||
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
|
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
|
||||||
|
|
||||||
|
// Substitute the conditional requirements so that they're phrased in terms of
|
||||||
|
// the specialized types, not the conformance-declaring decl's types.
|
||||||
|
auto subMap = getSubstitutionMap();
|
||||||
|
SmallVector<Requirement, 4> newReqs;
|
||||||
|
for (auto oldReq : GenericConformance->getConditionalRequirements()) {
|
||||||
|
newReqs.push_back(*oldReq.subst(subMap));
|
||||||
|
}
|
||||||
|
auto &ctxt = getProtocol()->getASTContext();
|
||||||
|
ConditionalRequirements = ctxt.AllocateCopy(newReqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
SubstitutionMap SpecializedProtocolConformance::getSubstitutionMap() const {
|
SubstitutionMap SpecializedProtocolConformance::getSubstitutionMap() const {
|
||||||
auto *genericSig = GenericConformance->getGenericSignature();
|
auto *genericSig = GenericConformance->getGenericSignature();
|
||||||
|
if (genericSig)
|
||||||
return genericSig->getSubstitutionMap(GenericSubstitutions);
|
return genericSig->getSubstitutionMap(GenericSubstitutions);
|
||||||
|
|
||||||
|
return SubstitutionMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpecializedProtocolConformance::hasTypeWitness(
|
bool SpecializedProtocolConformance::hasTypeWitness(
|
||||||
|
|||||||
@@ -1593,6 +1593,9 @@ namespace {
|
|||||||
FuncDecl *fn = nullptr;
|
FuncDecl *fn = nullptr;
|
||||||
|
|
||||||
if (bridgedToObjectiveCConformance) {
|
if (bridgedToObjectiveCConformance) {
|
||||||
|
assert(bridgedToObjectiveCConformance->getConditionalRequirements()
|
||||||
|
.empty() &&
|
||||||
|
"cannot conditionally conform to _BridgedToObjectiveC");
|
||||||
// The conformance to _BridgedToObjectiveC is statically known.
|
// The conformance to _BridgedToObjectiveC is statically known.
|
||||||
// Retrieve the bridging operation to be used if a static conformance
|
// Retrieve the bridging operation to be used if a static conformance
|
||||||
// to _BridgedToObjectiveC can be proven.
|
// to _BridgedToObjectiveC can be proven.
|
||||||
|
|||||||
@@ -2982,7 +2982,13 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
|
|||||||
// primitive literal protocols.
|
// primitive literal protocols.
|
||||||
auto conformsToProtocol = [&](KnownProtocolKind protoKind) {
|
auto conformsToProtocol = [&](KnownProtocolKind protoKind) {
|
||||||
ProtocolDecl *proto = TC.getProtocol(ED->getLoc(), protoKind);
|
ProtocolDecl *proto = TC.getProtocol(ED->getLoc(), protoKind);
|
||||||
return TC.conformsToProtocol(rawTy, proto, ED->getDeclContext(), None);
|
auto conformance =
|
||||||
|
TC.conformsToProtocol(rawTy, proto, ED->getDeclContext(), None);
|
||||||
|
if (conformance)
|
||||||
|
assert(conformance->getConditionalRequirements().empty() &&
|
||||||
|
"conditionally conforming to literal protocol not currently "
|
||||||
|
"supported");
|
||||||
|
return conformance;
|
||||||
};
|
};
|
||||||
|
|
||||||
static auto otherLiteralProtocolKinds = {
|
static auto otherLiteralProtocolKinds = {
|
||||||
|
|||||||
@@ -5968,6 +5968,9 @@ bool TypeChecker::useObjectiveCBridgeableConformances(DeclContext *dc,
|
|||||||
WasUnsatisfied |= result.hasUnsatisfiedDependency();
|
WasUnsatisfied |= result.hasUnsatisfiedDependency();
|
||||||
if (WasUnsatisfied)
|
if (WasUnsatisfied)
|
||||||
return Action::Stop;
|
return Action::Stop;
|
||||||
|
if (result.getStatus() == RequirementCheckResult::Success)
|
||||||
|
assert(result.getConformance().getConditionalRequirements().empty() &&
|
||||||
|
"cannot conform conditionally to _ObjectiveCBridgeable");
|
||||||
|
|
||||||
// Set and Dictionary bridging also requires the conformance
|
// Set and Dictionary bridging also requires the conformance
|
||||||
// of the key type to Hashable.
|
// of the key type to Hashable.
|
||||||
@@ -6062,6 +6065,9 @@ void TypeChecker::useBridgedNSErrorConformances(DeclContext *dc, Type type) {
|
|||||||
auto conformance = conformsToProtocol(type, bridgedStoredNSError, dc,
|
auto conformance = conformsToProtocol(type, bridgedStoredNSError, dc,
|
||||||
ConformanceCheckFlags::Used);
|
ConformanceCheckFlags::Used);
|
||||||
if (conformance && conformance->isConcrete()) {
|
if (conformance && conformance->isConcrete()) {
|
||||||
|
assert(conformance->getConditionalRequirements().empty() &&
|
||||||
|
"cannot conform condtionally to _BridgedStoredNSError");
|
||||||
|
|
||||||
// Hack: If we've used a conformance to the _BridgedStoredNSError
|
// Hack: If we've used a conformance to the _BridgedStoredNSError
|
||||||
// protocol, also use the RawRepresentable and _ErrorCodeProtocol
|
// protocol, also use the RawRepresentable and _ErrorCodeProtocol
|
||||||
// conformances on the Code associated type witness.
|
// conformances on the Code associated type witness.
|
||||||
@@ -6080,6 +6086,9 @@ void TypeChecker::useBridgedNSErrorConformances(DeclContext *dc, Type type) {
|
|||||||
(ConformanceCheckFlags::SuppressDependencyTracking|
|
(ConformanceCheckFlags::SuppressDependencyTracking|
|
||||||
ConformanceCheckFlags::Used));
|
ConformanceCheckFlags::Used));
|
||||||
if (conformance && conformance->isConcrete()) {
|
if (conformance && conformance->isConcrete()) {
|
||||||
|
assert(conformance->getConditionalRequirements().empty() &&
|
||||||
|
"cannot conform condtionally to _ErrorCodeProtocol");
|
||||||
|
|
||||||
if (Type errorType = ProtocolConformanceRef::getTypeWitnessByName(
|
if (Type errorType = ProtocolConformanceRef::getTypeWitnessByName(
|
||||||
type, *conformance, Context.Id_ErrorType, this)) {
|
type, *conformance, Context.Id_ErrorType, this)) {
|
||||||
(void)conformsToProtocol(errorType, bridgedStoredNSError, dc,
|
(void)conformsToProtocol(errorType, bridgedStoredNSError, dc,
|
||||||
|
|||||||
@@ -614,6 +614,9 @@ public:
|
|||||||
if (!conformance)
|
if (!conformance)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
assert(conformance->getConditionalRequirements().empty() &&
|
||||||
|
"conditionally conforming to Sequence is not currently supported");
|
||||||
|
|
||||||
generatorTy = TC.getWitnessType(sequenceType, sequenceProto,
|
generatorTy = TC.getWitnessType(sequenceType, sequenceProto,
|
||||||
*conformance,
|
*conformance,
|
||||||
TC.Context.Id_Iterator,
|
TC.Context.Id_Iterator,
|
||||||
@@ -664,6 +667,9 @@ public:
|
|||||||
sequence->getLoc());
|
sequence->getLoc());
|
||||||
if (!genConformance)
|
if (!genConformance)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
assert(
|
||||||
|
genConformance->getConditionalRequirements().empty() &&
|
||||||
|
"conditionally conforming to IteratorProtocol not currently supported");
|
||||||
|
|
||||||
Type elementTy = TC.getWitnessType(generatorTy, generatorProto,
|
Type elementTy = TC.getWitnessType(generatorTy, generatorProto,
|
||||||
*genConformance, TC.Context.Id_Element,
|
*genConformance, TC.Context.Id_Element,
|
||||||
|
|||||||
Reference in New Issue
Block a user