Skip to content
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
4 changes: 3 additions & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2272,12 +2272,14 @@ NOTE(candidate_types_equal_requirement,none,
(Type, Type, Type, Type))
NOTE(candidate_types_same_shape_requirement,none,
"candidate requires that the type packs %0 and %1 have the same shape "
"(requirement specified as %2.shape == %3.shape)",
"(same-shape requirement inferred between %2 and %3)",
(Type, Type, Type, Type))
NOTE(candidate_types_inheritance_requirement,none,
"candidate requires that %1 inherit from %2 "
"(requirement specified as %2 : %3)",
(Type, Type, Type, Type))
NOTE(same_shape_requirement,none,
"same-shape requirement inferred between %0 and %1%2", (Type, Type, StringRef))
NOTE(types_not_equal_requirement,none,
"requirement specified as %0 == %1%2", (Type, Type, StringRef))
ERROR(type_is_not_a_class,none,
Expand Down
31 changes: 27 additions & 4 deletions include/swift/AST/Requirement.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@

namespace swift {

/// Return type of Requirement::checkRequirement().
enum class CheckRequirementResult : uint8_t {
/// The requirement was fully satisfied.
Success,

/// The subject type conforms conditionally; the sub-requirements are
/// conditional requirements which must be checked.
ConditionalConformance,

/// The subject type is a pack type; the sub-requirements are the
/// element-wise requirements which must be checked.
PackRequirement,

/// The requirement cannot ever be satisfied.
RequirementFailure,

/// Some other requirement is expected to fail, or there was an invalid
/// conformance and an error should be diagnosed elsewhere, so this
/// requirement does not need to be diagnosed.
SubstitutionFailure
};

/// A single requirement placed on the type parameters (or associated
/// types thereof) of a
class Requirement {
Expand Down Expand Up @@ -155,11 +177,12 @@ class Requirement {

/// Determines if this substituted requirement is satisfied.
///
/// \param conditionalRequirements An out parameter initialized to an
/// array of requirements that the caller must check to ensure this
/// \param subReqs An out parameter initialized to a list of simpler
/// requirements which the caller must check to ensure this
/// requirement is completely satisfied.
bool isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
bool allowMissing = false) const;
CheckRequirementResult checkRequirement(
SmallVectorImpl<Requirement> &subReqs,
bool allowMissing = false) const;

/// Determines if this substituted requirement can ever be satisfied,
/// possibly with additional substitutions.
Expand Down
20 changes: 17 additions & 3 deletions lib/AST/GenericSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,10 +405,24 @@ bool GenericSignatureImpl::isRequirementSatisfied(
LookUpConformanceInSignature(this));
}

// FIXME: Need to check conditional requirements here.
ArrayRef<Requirement> conditionalRequirements;
SmallVector<Requirement, 2> subReqs;
switch (requirement.checkRequirement(subReqs, allowMissing)) {
case CheckRequirementResult::Success:
return true;

case CheckRequirementResult::ConditionalConformance:
// FIXME: Need to check conditional requirements here.
return true;

return requirement.isSatisfied(conditionalRequirements, allowMissing);
case CheckRequirementResult::PackRequirement:
// FIXME
assert(false && "Refactor this");
return true;

case CheckRequirementResult::RequirementFailure:
case CheckRequirementResult::SubstitutionFailure:
return false;
}
}

SmallVector<Requirement, 4>
Expand Down
86 changes: 70 additions & 16 deletions lib/AST/Requirement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,45 +76,99 @@ ProtocolDecl *Requirement::getProtocolDecl() const {
return getSecondType()->castTo<ProtocolType>()->getDecl();
}

bool
Requirement::isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
bool allowMissing) const {
CheckRequirementResult Requirement::checkRequirement(
SmallVectorImpl<Requirement> &subReqs,
bool allowMissing) const {
if (hasError())
return CheckRequirementResult::SubstitutionFailure;

auto firstType = getFirstType();

auto expandPackRequirement = [&](PackType *packType) {
for (auto eltType : packType->getElementTypes()) {
// FIXME: Doesn't seem right
if (auto *expansionType = eltType->getAs<PackExpansionType>())
eltType = expansionType->getPatternType();

auto kind = getKind();
if (kind == RequirementKind::Layout) {
subReqs.emplace_back(kind, eltType,
getLayoutConstraint());
} else {
subReqs.emplace_back(kind, eltType,
getSecondType());
}
}
return CheckRequirementResult::PackRequirement;
};

switch (getKind()) {
case RequirementKind::Conformance: {
if (auto packType = firstType->getAs<PackType>()) {
return expandPackRequirement(packType);
}

auto *proto = getProtocolDecl();
auto *module = proto->getParentModule();
auto conformance = module->lookupConformance(
getFirstType(), proto, allowMissing);
firstType, proto, allowMissing);
if (!conformance)
return false;
return CheckRequirementResult::RequirementFailure;

conditionalRequirements = conformance.getConditionalRequirements();
return true;
auto condReqs = conformance.getConditionalRequirements();
if (condReqs.empty())
return CheckRequirementResult::Success;
subReqs.append(condReqs.begin(), condReqs.end());
return CheckRequirementResult::ConditionalConformance;
}

case RequirementKind::Layout: {
if (auto *archetypeType = getFirstType()->getAs<ArchetypeType>()) {
if (auto packType = firstType->getAs<PackType>()) {
return expandPackRequirement(packType);
}

if (auto *archetypeType = firstType->getAs<ArchetypeType>()) {
auto layout = archetypeType->getLayoutConstraint();
return (layout && layout.merge(getLayoutConstraint()));
if (layout && layout.merge(getLayoutConstraint()))
return CheckRequirementResult::Success;

return CheckRequirementResult::RequirementFailure;
}

if (getLayoutConstraint()->isClass())
return getFirstType()->satisfiesClassConstraint();
if (getLayoutConstraint()->isClass()) {
if (firstType->satisfiesClassConstraint())
return CheckRequirementResult::Success;

return CheckRequirementResult::RequirementFailure;
}

// TODO: Statically check other layout constraints, once they can
// be spelled in Swift.
return true;
return CheckRequirementResult::Success;
}

case RequirementKind::Superclass:
return getSecondType()->isExactSuperclassOf(getFirstType());
if (auto packType = firstType->getAs<PackType>()) {
return expandPackRequirement(packType);
}

if (getSecondType()->isExactSuperclassOf(firstType))
return CheckRequirementResult::Success;

return CheckRequirementResult::RequirementFailure;

case RequirementKind::SameType:
return getFirstType()->isEqual(getSecondType());
if (firstType->isEqual(getSecondType()))
return CheckRequirementResult::Success;

return CheckRequirementResult::RequirementFailure;

case RequirementKind::SameShape:
return (getFirstType()->getReducedShape() ==
getSecondType()->getReducedShape());
if (firstType->getReducedShape() ==
getSecondType()->getReducedShape())
return CheckRequirementResult::Success;

return CheckRequirementResult::RequirementFailure;
}

llvm_unreachable("Bad requirement kind");
Expand Down
22 changes: 18 additions & 4 deletions lib/IDE/IDETypeChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,16 +344,30 @@ struct SynthesizedExtensionAnalyzer::Implementation {
return type;
},
LookUpConformanceInModule(M));
if (SubstReq.hasError())

SmallVector<Requirement, 2> subReqs;
switch (SubstReq.checkRequirement(subReqs)) {
case CheckRequirementResult::Success:
break;

case CheckRequirementResult::ConditionalConformance:
// FIXME: Need to handle conditional requirements here!
break;

case CheckRequirementResult::PackRequirement:
// FIXME
assert(false && "Refactor this");
return true;

case CheckRequirementResult::SubstitutionFailure:
return true;

// FIXME: Need to handle conditional requirements here!
ArrayRef<Requirement> conditionalRequirements;
if (!SubstReq.isSatisfied(conditionalRequirements)) {
case CheckRequirementResult::RequirementFailure:
if (!SubstReq.canBeSatisfied())
return true;

MergeInfo.addRequirement(Req);
break;
}
}
return false;
Expand Down
Loading