Skip to content

[Stdlib] Use associated type where clauses to address various ABI FIXMEs. #8593

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 9 commits into from
Apr 20, 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
31 changes: 26 additions & 5 deletions include/swift/AST/GenericSignatureBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ class GenericSignatureBuilder {
/// Determine whether conformance to the given protocol is satisfied by
/// a superclass requirement.
bool isConformanceSatisfiedBySuperclass(ProtocolDecl *proto) const;

/// Dump a debugging representation of this equivalence class.
void dump(llvm::raw_ostream &out) const;

LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
"only for use in the debugger");
};

friend class RequirementSource;
Expand Down Expand Up @@ -1102,6 +1108,9 @@ class GenericSignatureBuilder::FloatingRequirementSource {
Inferred,
/// A requirement source augmented by an abstract protocol requirement
AbstractProtocol,
/// A requirement source for a nested-type-name match introduced by
/// the given source.
NestedTypeNameMatch,
} kind;

using Storage =
Expand All @@ -1111,11 +1120,15 @@ class GenericSignatureBuilder::FloatingRequirementSource {
Storage storage;

// Additional storage for an abstract protocol requirement.
struct {
ProtocolDecl *protocol = nullptr;
WrittenRequirementLoc written;
bool inferred = false;
} protocolReq;
union {
struct {
ProtocolDecl *protocol = nullptr;
WrittenRequirementLoc written;
bool inferred = false;
} protocolReq;

Identifier nestedName;
};

FloatingRequirementSource(Kind kind, Storage storage)
: kind(kind), storage(storage) { }
Expand Down Expand Up @@ -1164,6 +1177,14 @@ class GenericSignatureBuilder::FloatingRequirementSource {
return result;
}

static FloatingRequirementSource forNestedTypeNameMatch(
const RequirementSource *base,
Identifier nestedName) {
FloatingRequirementSource result{ NestedTypeNameMatch, base };
result.nestedName = nestedName;
return result;
};

/// Retrieve the complete requirement source rooted at the given potential
/// archetype.
const RequirementSource *getSource(PotentialArchetype *pa) const;
Expand Down
119 changes: 108 additions & 11 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ static Type formProtocolRelativeType(ProtocolDecl *proto,
PotentialArchetype *basePA,
PotentialArchetype *pa) {
// Basis case: we've hit the base potential archetype.
if (basePA->isInSameEquivalenceClassAs(pa))
if (basePA == pa)
return proto->getSelfInterfaceType();

// Recursive case: form a dependent member type.
Expand Down Expand Up @@ -846,6 +846,9 @@ const RequirementSource *FloatingRequirementSource::getSource(
protocolReq.protocol, protocolReq.inferred,
protocolReq.written);
}

case NestedTypeNameMatch:
return RequirementSource::forNestedTypeNameMatch(pa);
}

llvm_unreachable("Unhandled FloatingPointRequirementSourceKind in switch.");
Expand Down Expand Up @@ -878,6 +881,7 @@ bool FloatingRequirementSource::isExplicit() const {
return true;

case Inferred:
case NestedTypeNameMatch:
return false;

case AbstractProtocol:
Expand Down Expand Up @@ -926,6 +930,7 @@ FloatingRequirementSource FloatingRequirementSource::asInferred(

case Inferred:
case Resolved:
case NestedTypeNameMatch:
return *this;

case AbstractProtocol:
Expand All @@ -941,7 +946,7 @@ bool FloatingRequirementSource::isRecursive(
llvm::SmallSet<std::pair<CanType, ProtocolDecl *>, 4> visitedAssocReqs;
for (auto storedSource = storage.dyn_cast<const RequirementSource *>();
storedSource; storedSource = storedSource->parent) {
if (storedSource->kind != RequirementSource::ProtocolRequirement)
if (!storedSource->isProtocolRequirement())
continue;

if (!visitedAssocReqs.insert(
Expand All @@ -950,6 +955,22 @@ bool FloatingRequirementSource::isRecursive(
return true;
}

// For a nested type match, look for another type with that name.
// FIXME: Actually, look for 5 of them. This is totally bogus.
if (kind == NestedTypeNameMatch) {
unsigned grossCount = 0;
auto pa = storage.dyn_cast<const RequirementSource *>()
->getAffectedPotentialArchetype();
while (auto parent = pa->getParent()) {
if (pa->getNestedName() == nestedName) {
if (++grossCount > 4) return true;
}


pa = parent;
}
}

return false;
}

Expand Down Expand Up @@ -1083,6 +1104,50 @@ bool EquivalenceClass::isConformanceSatisfiedBySuperclass(
return false;
}

void EquivalenceClass::dump(llvm::raw_ostream &out) const {
out << "Equivalence class represented by "
<< members.front()->getRepresentative()->getDebugName() << ":\n";
out << "Members: ";
interleave(members, [&](PotentialArchetype *pa) {
out << pa->getDebugName();
}, [&]() {
out << ", ";
});
out << "\nConformances:";
interleave(conformsTo,
[&](const std::pair<
ProtocolDecl *,
std::vector<Constraint<ProtocolDecl *>>> &entry) {
out << entry.first->getNameStr();
},
[&] { out << ", "; });
out << "\nSame-type constraints:";
for (const auto &entry : sameTypeConstraints) {
out << "\n " << entry.first->getDebugName() << " == ";
interleave(entry.second,
[&](const Constraint<PotentialArchetype *> &constraint) {
out << constraint.value->getDebugName();

if (constraint.source->isDerivedRequirement())
out << " [derived]";
}, [&] {
out << ", ";
});
}
if (concreteType)
out << "\nConcrete type: " << concreteType.getString();
if (superclass)
out << "\nSuperclass: " << superclass.getString();
if (layout)
out << "\nLayout: " << layout.getString();

out << "\n";
}

void EquivalenceClass::dump() const {
dump(llvm::errs());
}

ConstraintResult GenericSignatureBuilder::handleUnresolvedRequirement(
RequirementKind kind,
UnresolvedType lhs,
Expand Down Expand Up @@ -1398,7 +1463,13 @@ PotentialArchetype *PotentialArchetype::getArchetypeAnchor(
if (auto parent = getParent()) {
// For a nested type, retrieve the parent archetype anchor first.
auto parentAnchor = parent->getArchetypeAnchor(builder);
anchor = parentAnchor->getNestedArchetypeAnchor(getNestedName(), builder);
anchor = parentAnchor->getNestedArchetypeAnchor(
getNestedName(), builder,
NestedTypeUpdate::ResolveExisting);

// FIXME: Hack for cases where we couldn't resolve the nested type.
if (!anchor)
anchor = rep;
} else {
anchor = rep;
}
Expand Down Expand Up @@ -2791,14 +2862,16 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
}

// Recursively merge the associated types of T2 into T1.
auto dependentT1 = T1->getDependentType({ }, /*allowUnresolved=*/true);
for (auto equivT2 : equivClass2Members) {
for (auto T2Nested : equivT2->NestedTypes) {
auto T1Nested = T1->getNestedType(T2Nested.first, *this);
if (isErrorResult(addSameTypeRequirement(
T1Nested, T2Nested.second.front(),
RequirementSource::forNestedTypeNameMatch(T1Nested),
UnresolvedHandlingKind::GenerateConstraints,
DiagnoseSameTypeConflict{Diags, Source, T1Nested})))
Type nestedT1 = DependentMemberType::get(dependentT1, T2Nested.first);
if (isErrorResult(
addSameTypeRequirement(
nestedT1, T2Nested.second.front(),
FloatingRequirementSource::forNestedTypeNameMatch(
Source, T2Nested.first),
UnresolvedHandlingKind::GenerateConstraints)))
return ConstraintResult::Conflicting;
}
}
Expand Down Expand Up @@ -3809,8 +3882,12 @@ Constraint<T> GenericSignatureBuilder::checkConstraintList(

namespace {
/// Remove self-derived sources from the given vector of constraints.
///
/// \returns true if any derived-via-concrete constraints were found.
template<typename T>
void removeSelfDerived(std::vector<Constraint<T>> &constraints) {
bool removeSelfDerived(std::vector<Constraint<T>> &constraints,
bool dropDerivedViaConcrete = true) {
bool anyDerivedViaConcrete = false;
// Remove self-derived constraints.
Optional<Constraint<T>> remainingConcrete;
constraints.erase(
Expand All @@ -3824,6 +3901,11 @@ namespace {
if (!derivedViaConcrete)
return false;

anyDerivedViaConcrete = true;

if (!dropDerivedViaConcrete)
return false;

// Drop derived-via-concrete requirements.
if (!remainingConcrete)
remainingConcrete = constraint;
Expand All @@ -3836,6 +3918,7 @@ namespace {
constraints.push_back(*remainingConcrete);

assert(!constraints.empty() && "All constraints were self-derived!");
return anyDerivedViaConcrete;
}
}

Expand Down Expand Up @@ -4191,11 +4274,13 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
equivClass = pa->getEquivalenceClassIfPresent();
assert(equivClass && "Equivalence class disappeared?");

bool anyDerivedViaConcrete = false;
for (auto &entry : equivClass->sameTypeConstraints) {
auto &constraints = entry.second;

// Remove self-derived constraints.
removeSelfDerived(constraints);
if (removeSelfDerived(constraints, /*dropDerivedViaConcrete=*/false))
anyDerivedViaConcrete = true;

// Sort the constraints, so we get a deterministic ordering of diagnostics.
llvm::array_pod_sort(constraints.begin(), constraints.end());
Expand Down Expand Up @@ -4272,6 +4357,18 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
}
}

// If there were any derived-via-concrete constraints, drop them now before
// we emit other diagnostics.
if (anyDerivedViaConcrete) {
for (auto &entry : equivClass->sameTypeConstraints) {
auto &constraints = entry.second;

// Remove derived-via-concrete constraints.
(void)removeSelfDerived(constraints);
anyDerivedViaConcrete = true;
}
}

// Walk through each of the components, checking the intracomponent edges.
// This will diagnose any explicitly-specified requirements within a
// component, all of which are redundant.
Expand Down
Loading