Skip to content

[WIP] [Stdlib] Eliminate SubSequence from _Indexable. #9276

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

Closed
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
18 changes: 12 additions & 6 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,15 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {

/// Retrieve the type witness for the given associated type.
Type getTypeWitness(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const;
LazyResolver *resolver,
SubstOptions options = None) const;

/// Retrieve the type witness and type decl (if one exists)
/// for the given associated type.
std::pair<Type, TypeDecl *>
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const;
LazyResolver *resolver,
SubstOptions options = None) const;

/// Apply the given function object to each type witness within this
/// protocol conformance.
Expand Down Expand Up @@ -399,7 +401,8 @@ class NormalProtocolConformance : public ProtocolConformance,
/// for the given associated type.
std::pair<Type, TypeDecl *>
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const;
LazyResolver *resolver,
SubstOptions options = None) const;

/// Determine whether the protocol conformance has a type witness for the
/// given associated type.
Expand Down Expand Up @@ -568,7 +571,8 @@ class SpecializedProtocolConformance : public ProtocolConformance,
/// for the given associated type.
std::pair<Type, TypeDecl *>
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const;
LazyResolver *resolver,
SubstOptions options = None) const;

/// Given that the requirement signature of the protocol directly states
/// that the given dependent type must conform to the given protocol,
Expand Down Expand Up @@ -662,8 +666,10 @@ class InheritedProtocolConformance : public ProtocolConformance,
/// for the given associated type.
std::pair<Type, TypeDecl *>
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const {
return InheritedConformance->getTypeWitnessAndDecl(assocType, resolver);
LazyResolver *resolver,
SubstOptions options = None) const {
return InheritedConformance->getTypeWitnessAndDecl(assocType, resolver,
options);
}

/// Given that the requirement signature of the protocol directly states
Expand Down
21 changes: 20 additions & 1 deletion include/swift/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,26 @@ enum class SubstFlags {
};

/// Options for performing substitutions into a type.
typedef OptionSet<SubstFlags> SubstOptions;
struct SubstOptions : public OptionSet<SubstFlags> {
typedef std::function<Type(const NormalProtocolConformance *,
AssociatedTypeDecl *)>
GetTentativeTypeWitness;

/// Function that retrieves a tentative type witness for a protocol
/// conformance with the state \c CheckingTypeWitnesses.
GetTentativeTypeWitness getTentativeTypeWitness;

SubstOptions(llvm::NoneType) : OptionSet(None) { }

SubstOptions(SubstFlags flags) : OptionSet(flags) { }

SubstOptions(OptionSet<SubstFlags> options) : OptionSet(options) { }

SubstOptions(OptionSet<SubstFlags> options,
GetTentativeTypeWitness getTentativeTypeWitness)
: OptionSet(options),
getTentativeTypeWitness(std::move(getTentativeTypeWitness)) { }
};

inline SubstOptions operator|(SubstFlags lhs, SubstFlags rhs) {
return SubstOptions(lhs) | rhs;
Expand Down
86 changes: 61 additions & 25 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,16 @@ ProtocolConformance::hasTypeWitness(AssociatedTypeDecl *assocType,

std::pair<Type, TypeDecl *>
ProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const {
CONFORMANCE_SUBCLASS_DISPATCH(getTypeWitnessAndDecl, (assocType, resolver))
LazyResolver *resolver,
SubstOptions options) const {
CONFORMANCE_SUBCLASS_DISPATCH(getTypeWitnessAndDecl,
(assocType, resolver, options))
}

Type ProtocolConformance::getTypeWitness(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const {
return getTypeWitnessAndDecl(assocType, resolver).first;
LazyResolver *resolver,
SubstOptions options) const {
return getTypeWitnessAndDecl(assocType, resolver, options).first;
}

ValueDecl *ProtocolConformance::getWitnessDecl(ValueDecl *requirement,
Expand Down Expand Up @@ -472,22 +475,39 @@ static bool resolveKnownTypeWitness(NormalProtocolConformance *conformance,

std::pair<Type, TypeDecl *>
NormalProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
LazyResolver *resolver) const {
LazyResolver *resolver,
SubstOptions options) const {
if (Resolver)
resolveLazyInfo();

// Check whether we already have a type witness.
auto known = TypeWitnesses.find(assocType);
if (known == TypeWitnesses.end()) {
PrettyStackTraceRequirement trace("resolving", this, assocType);
if (!resolveKnownTypeWitness(const_cast<NormalProtocolConformance *>(this),
assocType)) {
assert(resolver && "Unable to resolve type witness");
resolver->resolveTypeWitness(this, assocType);
if (known != TypeWitnesses.end())
return known->second;

// If this conformance is in a state where it is inferring type witnesses,
// check tentative witnesses.
if (getState() == ProtocolConformanceState::CheckingTypeWitnesses) {
// If there is a tentative-type-witness function, use it.
if (options.getTentativeTypeWitness) {
if (Type witnessType = options.getTentativeTypeWitness(this, assocType))
return { witnessType, nullptr };
}
known = TypeWitnesses.find(assocType);
assert(known != TypeWitnesses.end() && "Didn't resolve witness?");

// Otherwise, we fail; this is the only case in which we can retturn a
// null type.
return { Type(), nullptr };
}

// Otherwise, resolve the type witness.
PrettyStackTraceRequirement trace("resolving", this, assocType);
if (!resolveKnownTypeWitness(const_cast<NormalProtocolConformance *>(this),
assocType)) {
assert(resolver && "Unable to resolve type witness");
resolver->resolveTypeWitness(this, assocType);
}
known = TypeWitnesses.find(assocType);
assert(known != TypeWitnesses.end() && "Didn't resolve witness?");
return known->second;
}

Expand Down Expand Up @@ -656,7 +676,8 @@ bool SpecializedProtocolConformance::hasTypeWitness(
std::pair<Type, TypeDecl *>
SpecializedProtocolConformance::getTypeWitnessAndDecl(
AssociatedTypeDecl *assocType,
LazyResolver *resolver) const {
LazyResolver *resolver,
SubstOptions options) const {
// If we've already created this type witness, return it.
auto known = TypeWitnesses.find(assocType);
if (known != TypeWitnesses.end()) {
Expand All @@ -669,26 +690,41 @@ SpecializedProtocolConformance::getTypeWitnessAndDecl(
auto substitutionMap =
genericSig->getSubstitutionMap(GenericSubstitutions);

// Local function to determine whether we will end up
auto normal = GenericConformance->getRootNormalConformance();
auto isTentativeWitness = [&] {
if (normal->getState() != ProtocolConformanceState::CheckingTypeWitnesses)
return false;

return !normal->hasTypeWitness(assocType, nullptr);
};

auto genericWitnessAndDecl
= GenericConformance->getTypeWitnessAndDecl(assocType, resolver);
= GenericConformance->getTypeWitnessAndDecl(assocType, resolver, options);

auto genericWitness = genericWitnessAndDecl.first;
if (!genericWitness)
return { Type(), nullptr };

auto &genericWitness = genericWitnessAndDecl.first;
auto *typeDecl = genericWitnessAndDecl.second;

// Apply the substitution we computed above
auto specializedType
= genericWitness.subst(substitutionMap);
if (!specializedType)
specializedType = ErrorType::get(genericWitness);
= genericWitness.subst(substitutionMap, options);
if (!specializedType) {
if (isTentativeWitness())
return { Type(), nullptr };

// If the type witness was unchanged, just copy it directly.
if (specializedType.getPointer() == genericWitness.getPointer()) {
TypeWitnesses[assocType] = genericWitnessAndDecl;
return TypeWitnesses[assocType];
specializedType = ErrorType::get(genericWitness);
}

TypeWitnesses[assocType] = std::make_pair(specializedType, typeDecl);
return TypeWitnesses[assocType];
// If we aren't in a case where we used the tentative type witness
// information, cache the result.
auto specializedWitnessAndDecl = std::make_pair(specializedType, typeDecl);
if (!isTentativeWitness() && !specializedType->hasError())
TypeWitnesses[assocType] = specializedWitnessAndDecl;

return specializedWitnessAndDecl;
}

ProtocolConformanceRef
Expand Down
14 changes: 4 additions & 10 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2909,17 +2909,11 @@ static Type getMemberForBaseType(LookupConformanceFn lookupConformances,
if (!conformance) return failed();
if (!conformance->isConcrete()) return failed();

// If we have an unsatisfied type witness while we're checking the
// conformances we're supposed to skip this conformance's unsatisfied type
// witnesses, and we have an unsatisfied type witness, return
// "missing".
if (conformance->getConcrete()->getRootNormalConformance()->getState()
== ProtocolConformanceState::CheckingTypeWitnesses &&
!conformance->getConcrete()->hasTypeWitness(assocType, nullptr))
return failed();

// Retrieve the type witness.
auto witness =
conformance->getConcrete()->getTypeWitness(assocType, resolver);
conformance->getConcrete()->getTypeWitness(assocType, resolver, options);
if (!witness)
return failed();

// This is a hacky feature allowing code completion to migrate to
// using Type::subst() without changing output.
Expand Down
42 changes: 24 additions & 18 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1246,11 +1246,12 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
LookupConformanceFn conformances,
UnsatisfiedDependency *unsatisfiedDependency,
ConformanceCheckOptions conformanceOptions,
GenericRequirementsCheckListener *listener) {
GenericRequirementsCheckListener *listener,
SubstOptions options) {
bool valid = true;

for (const auto &rawReq : genericSig->getRequirements()) {
auto req = rawReq.subst(substitutions, conformances);
auto req = rawReq.subst(substitutions, conformances, options);
if (!req) {
// Another requirement will fail later; just continue.
valid = false;
Expand Down Expand Up @@ -1286,6 +1287,7 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
switch (status) {
case RequirementCheckResult::UnsatisfiedDependency:
case RequirementCheckResult::Failure:
case RequirementCheckResult::SubstitutionFailure:
// pass it on up.
return status;
case RequirementCheckResult::Success:
Expand All @@ -1308,28 +1310,32 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
case RequirementKind::Superclass:
// Superclass requirements.
if (!isSubtypeOf(firstType, secondType, dc)) {
// FIXME: Poor source-location information.
diagnose(loc, diag::type_does_not_inherit, owner, firstType,
secondType);

diagnose(noteLoc, diag::type_does_not_inherit_requirement, rawFirstType,
rawSecondType,
genericSig->gatherGenericParamBindingsText(
{rawFirstType, rawSecondType}, substitutions));
if (loc.isValid()) {
// FIXME: Poor source-location information.
diagnose(loc, diag::type_does_not_inherit, owner, firstType,
secondType);

diagnose(noteLoc, diag::type_does_not_inherit_requirement,
rawFirstType, rawSecondType,
genericSig->gatherGenericParamBindingsText(
{rawFirstType, rawSecondType}, substitutions));
}

return RequirementCheckResult::Failure;
}
continue;

case RequirementKind::SameType:
if (!firstType->isEqual(secondType)) {
// FIXME: Better location info for both diagnostics.
diagnose(loc, diag::types_not_equal, owner, firstType, secondType);

diagnose(noteLoc, diag::types_not_equal_requirement, rawFirstType,
rawSecondType,
genericSig->gatherGenericParamBindingsText(
{rawFirstType, rawSecondType}, substitutions));
if (loc.isValid()) {
// FIXME: Better location info for both diagnostics.
diagnose(loc, diag::types_not_equal, owner, firstType, secondType);

diagnose(noteLoc, diag::types_not_equal_requirement, rawFirstType,
rawSecondType,
genericSig->gatherGenericParamBindingsText(
{rawFirstType, rawSecondType}, substitutions));
}

return RequirementCheckResult::Failure;
}
Expand All @@ -1339,5 +1345,5 @@ RequirementCheckResult TypeChecker::checkGenericArguments(

if (valid)
return RequirementCheckResult::Success;
return RequirementCheckResult::Failure;
return RequirementCheckResult::SubstitutionFailure;
}
Loading