Skip to content

[GSB] Introduce resolveEquivalenceClass() and start using it. #11833

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions include/swift/AST/GenericSignatureBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,21 @@ class GenericSignatureBuilder {
ArchetypeResolutionKind resolutionKind);

public:
/// \brief Resolve the equivalence class for the given type parameter,
/// which provides information about that type.
///
/// The \c resolutionKind parameter describes how resolution should be
/// performed. If the potential archetype named by the given dependent type
/// already exists, it will be always returned. If it doesn't exist yet,
/// the \c resolutionKind dictates whether the potential archetype will
/// be created or whether null will be returned.
///
/// For any type that cannot refer to an equivalence class, this routine
/// returns null.
EquivalenceClass *resolveEquivalenceClass(
Type type,
ArchetypeResolutionKind resolutionKind);

/// \brief Resolve the given type to the potential archetype it names.
///
/// The \c resolutionKind parameter describes how resolution should be
Expand Down
124 changes: 63 additions & 61 deletions lib/AST/GenericSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,31 +484,27 @@ bool GenericSignature::requiresClass(Type type, ModuleDecl &mod) {
if (!type->isTypeParameter()) return false;

auto &builder = *getGenericSignatureBuilder(mod);
auto pa =
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return false;

if (pa->isConcreteType()) return false;
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.
pa = pa->getRepresentative();

if (pa->isConcreteType()) return false;
if (equivClass->concreteType) return false;

// If there is a layout constraint, it might be a class.
if (auto layout = pa->getLayout()) {
if (layout->isClass()) return true;
}
if (equivClass->layout && equivClass->layout->isClass()) return true;

// If there is a superclass bound, then obviously it must be a class.
// FIXME: We shouldn't need this?
if (pa->getSuperclass()) return true;
if (equivClass->superclass) return true;

// If any of the protocols are class-bound, then it must be a class.
// FIXME: We shouldn't need this?
for (auto proto : pa->getConformsTo()) {
if (proto->requiresClass()) return true;
for (const auto &conforms : equivClass->conformsTo) {
if (conforms.first->requiresClass()) return true;
}

return false;
Expand All @@ -519,37 +515,41 @@ Type GenericSignature::getSuperclassBound(Type type, ModuleDecl &mod) {
if (!type->isTypeParameter()) return nullptr;

auto &builder = *getGenericSignatureBuilder(mod);
auto pa =
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return nullptr;
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 (pa->isConcreteType()) return nullptr;
if (equivClass->concreteType) return nullptr;

// Retrieve the superclass bound.
return pa->getSuperclass();
return equivClass->superclass;
}

/// Determine the set of protocols to which the given dependent type
/// must conform.
SmallVector<ProtocolDecl *, 2> GenericSignature::getConformsTo(Type type,
ModuleDecl &mod) {
SmallVector<ProtocolDecl *, 2>
GenericSignature::getConformsTo(Type type, ModuleDecl &mod) {
if (!type->isTypeParameter()) return { };

auto &builder = *getGenericSignatureBuilder(mod);
auto pa =
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return { };
auto equivClass =
builder.resolveEquivalenceClass(
type,
ArchetypeResolutionKind::CompleteWellFormed);
if (!equivClass) return { };

// If this type was mapped to a concrete type, then there are no
// requirements.
if (pa->isConcreteType()) return { };
if (equivClass->concreteType) return { };

// Retrieve the protocols to which this type conforms.
SmallVector<ProtocolDecl *, 2> result;
for (auto proto : pa->getConformsTo())
result.push_back(proto);
for (const auto &conforms : equivClass->conformsTo)
result.push_back(conforms.first);

// Canonicalize the resulting set of protocols.
ProtocolType::canonicalizeProtocols(result);
Expand All @@ -563,19 +563,17 @@ bool GenericSignature::conformsToProtocol(Type type, ProtocolDecl *proto,
if (!type->isTypeParameter()) return false;

auto &builder = *getGenericSignatureBuilder(mod);
auto pa =
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return false;
auto equivClass =
builder.resolveEquivalenceClass(
type,
ArchetypeResolutionKind::CompleteWellFormed);
if (!equivClass) return false;

// FIXME: Deal with concrete conformances here?
if (pa->isConcreteType()) return false;
if (equivClass->concreteType) return false;

// Check whether the representative conforms to this protocol.
if (auto equivClass = pa->getEquivalenceClassIfPresent())
if (equivClass->conformsTo.count(proto) > 0)
return true;

return false;
return equivClass->conformsTo.count(proto) > 0;
}

/// Determine whether the given dependent type is equal to a concrete type.
Expand All @@ -590,23 +588,27 @@ Type GenericSignature::getConcreteType(Type type, ModuleDecl &mod) {
if (!type->isTypeParameter()) return Type();

auto &builder = *getGenericSignatureBuilder(mod);
auto pa =
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return Type();
auto equivClass =
builder.resolveEquivalenceClass(
type,
ArchetypeResolutionKind::CompleteWellFormed);
if (!equivClass) return Type();

return pa->getConcreteType();
return equivClass->concreteType;
}

LayoutConstraint GenericSignature::getLayoutConstraint(Type type,
ModuleDecl &mod) {
if (!type->isTypeParameter()) return LayoutConstraint();

auto &builder = *getGenericSignatureBuilder(mod);
auto pa =
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return LayoutConstraint();
auto equivClass =
builder.resolveEquivalenceClass(
type,
ArchetypeResolutionKind::CompleteWellFormed);
if (!equivClass) return LayoutConstraint();

return pa->getLayout();
return equivClass->layout;
}

bool GenericSignature::areSameTypeParameterInContext(Type type1, Type type2,
Expand All @@ -618,21 +620,21 @@ bool GenericSignature::areSameTypeParameterInContext(Type type1, Type type2,
return true;

auto &builder = *getGenericSignatureBuilder(mod);
auto pa1 =
builder.resolveArchetype(type1,
auto equivClass1 =
builder.resolveEquivalenceClass(
type1,
ArchetypeResolutionKind::CompleteWellFormed);
assert(pa1 && "not a valid dependent type of this signature?");
pa1 = pa1->getRepresentative();
assert(!pa1->isConcreteType());
assert(equivClass1 && "not a valid dependent type of this signature?");
assert(!equivClass1->concreteType);

auto pa2 =
builder.resolveArchetype(type2,
auto equivClass2 =
builder.resolveEquivalenceClass(
type2,
ArchetypeResolutionKind::CompleteWellFormed);
assert(pa2 && "not a valid dependent type of this signature?");
pa2 = pa2->getRepresentative();
assert(!pa2->isConcreteType());
assert(equivClass2 && "not a valid dependent type of this signature?");
assert(!equivClass2->concreteType);

return pa1 == pa2;
return equivClass1 == equivClass2;
}

bool GenericSignature::isCanonicalTypeInContext(Type type, ModuleDecl &mod) {
Expand Down Expand Up @@ -772,9 +774,10 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(

// Resolve this type to a potential archetype.
auto &builder = *getGenericSignatureBuilder(mod);
auto pa =
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
auto equivClass = pa->getOrCreateEquivalenceClass();
auto equivClass =
builder.resolveEquivalenceClass(
type,
ArchetypeResolutionKind::CompleteWellFormed);

// Dig out the conformance of this type to the given protocol, because we
// want its requirement source.
Expand Down Expand Up @@ -873,11 +876,10 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
Type storedType = eraseAssociatedTypes(source->getStoredType());

// Dig out the potential archetype for this stored type.
auto pa =
inProtoSigBuilder.resolveArchetype(
auto equivClass =
inProtoSigBuilder.resolveEquivalenceClass(
storedType,
ArchetypeResolutionKind::CompleteWellFormed);
auto equivClass = pa->getOrCreateEquivalenceClass();

// Find the conformance of this potential archetype to the protocol in
// question.
Expand Down
9 changes: 9 additions & 0 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2770,6 +2770,15 @@ auto GenericSignatureBuilder::resolvePotentialArchetype(
return (EquivalenceClass *)nullptr;
}

EquivalenceClass *GenericSignatureBuilder::resolveEquivalenceClass(
Type type,
ArchetypeResolutionKind resolutionKind) {
auto pa = resolveArchetype(type, resolutionKind);
if (!pa) return nullptr;

return pa->getOrCreateEquivalenceClass();
}

PotentialArchetype *GenericSignatureBuilder::resolveArchetype(
Type type,
ArchetypeResolutionKind resolutionKind) {
Expand Down
26 changes: 13 additions & 13 deletions lib/AST/LookupVisibleDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,26 +564,26 @@ static void lookupVisibleMemberDeclsImpl(
// If we're looking into a type parameter and we have a generic signature
// builder, use the GSB to resolve where we should look.
if (BaseTy->isTypeParameter() && GSB) {
auto PA = GSB->resolveArchetype(
BaseTy,
ArchetypeResolutionKind::CompleteWellFormed);
if (!PA) return;
auto EquivClass =
GSB->resolveEquivalenceClass(BaseTy,
ArchetypeResolutionKind::CompleteWellFormed);
if (!EquivClass) return;

if (auto Concrete = PA->getConcreteType()) {
BaseTy = Concrete;
if (EquivClass->concreteType) {
BaseTy = EquivClass->concreteType;
} else {
// Conformances
for (auto Proto : PA->getConformsTo()) {
for (const auto &Conforms : EquivClass->conformsTo) {
lookupVisibleProtocolMemberDecls(
BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS,
getReasonForSuper(Reason), TypeResolver, GSB, Visited);
BaseTy, Conforms.first->getDeclaredType(), Consumer, CurrDC,
LS, getReasonForSuper(Reason), TypeResolver, GSB, Visited);
}

// Superclass.
if (auto Superclass = PA->getSuperclass()) {
lookupVisibleMemberDeclsImpl(Superclass, Consumer, CurrDC, LS,
getReasonForSuper(Reason), TypeResolver,
GSB, Visited);
if (EquivClass->superclass) {
lookupVisibleMemberDeclsImpl(EquivClass->superclass, Consumer, CurrDC,
LS, getReasonForSuper(Reason),
TypeResolver, GSB, Visited);
}
return;
}
Expand Down
14 changes: 8 additions & 6 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,16 @@ bool CompleteGenericTypeResolver::areSameType(Type type1, Type type2) {
if (!type1->hasTypeParameter() && !type2->hasTypeParameter())
return type1->isEqual(type2);

auto pa1 =
Builder.resolveArchetype(type1,
auto equivClass1 =
Builder.resolveEquivalenceClass(
type1,
ArchetypeResolutionKind::CompleteWellFormed);
auto pa2 =
Builder.resolveArchetype(type2,
auto equivClass2 =
Builder.resolveEquivalenceClass(
type2,
ArchetypeResolutionKind::CompleteWellFormed);
if (pa1 && pa2)
return pa1->isInSameEquivalenceClassAs(pa2);
if (equivClass1 && equivClass2)
return equivClass1 == equivClass2;

return type1->isEqual(type2);
}
Expand Down