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
6 changes: 6 additions & 0 deletions include/swift/AST/GenericSignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
void getSubstitutionMap(ArrayRef<Substitution> args,
SubstitutionMap &subMap) const;

/// Build an interface type substitution map from a type substitution function
/// and conformance lookup function.
SubstitutionMap
getSubstitutionMap(TypeSubstitutionFn subs,
LookupConformanceFn lookupConformance) const;

using GenericFunction = auto(CanType canType, Type conformingReplacementType,
ProtocolType *conformedProtocol)
->Optional<ProtocolConformanceRef>;
Expand Down
15 changes: 0 additions & 15 deletions include/swift/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,21 +249,6 @@ class Type {
});
}

/// Replace references to substitutable types with new, concrete types and
/// return the substituted result.
///
/// \param module The module to use for conformance lookups.
///
/// \param substitutions The mapping from substitutable types to their
/// replacements.
///
/// \param options Options that affect the substitutions.
///
/// \returns the substituted type, or a null type if an error occurred.
Type subst(ModuleDecl *module,
const TypeSubstitutionMap &substitutions,
SubstOptions options = None) const;

/// Replace references to substitutable types with new, concrete types and
/// return the substituted result.
///
Expand Down
13 changes: 9 additions & 4 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -873,13 +873,21 @@ class alignas(1 << TypeAlignInBits) TypeBase {
/// the context of the extension above will produce substitutions T
/// -> Int and U -> String suitable for mapping the type of
/// \c SomeArray.
SubstitutionMap getContextSubstitutionMap(ModuleDecl *module,
const DeclContext *dc);

/// Deprecated version of the above.
TypeSubstitutionMap getContextSubstitutions(const DeclContext *dc);

/// Get the substitutions to apply to the type of the given member as seen
/// from this base type.
///
/// If the member has its own generic parameters, they will remain unchanged
/// by the substitution.
SubstitutionMap getMemberSubstitutionMap(ModuleDecl *module,
const ValueDecl *member);

/// Deprecated version of the above.
TypeSubstitutionMap getMemberSubstitutions(const ValueDecl *member);

/// Retrieve the type of the given member as seen through the given base
Expand All @@ -903,16 +911,13 @@ class alignas(1 << TypeAlignInBits) TypeBase {
///
/// \param member The member whose type we are substituting.
///
/// \param resolver The resolver for lazy type checking, which may be null for
/// a fully-type-checked AST.
///
/// \param memberType The type of the member, in which archetypes will be
/// replaced by the generic arguments provided by the base type. If null,
/// the member's type will be used.
///
/// \returns the resulting member type.
Type getTypeOfMember(ModuleDecl *module, const ValueDecl *member,
LazyResolver *resolver, Type memberType = Type());
Type memberType = Type());

/// Get the type of a superclass member as seen from the subclass,
/// substituting generic parameters, dynamic Self return, and the
Expand Down
41 changes: 21 additions & 20 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,19 +224,18 @@ struct SynthesizedExtensionAnalyzer::Implementation {
// Get the substitutions from the generic signature of
// the extension to the interface types of the base type's
// declaration.
TypeSubstitutionMap subMap;
if (!BaseType->isExistentialType())
subMap = BaseType->getContextSubstitutions(Ext);
auto *M = DC->getParentModule();
SubstitutionMap subMap;
if (!BaseType->isExistentialType())
subMap = BaseType->getContextSubstitutionMap(M, Ext);

assert(Ext->getGenericSignature() && "No generic signature.");
for (auto Req : Ext->getGenericSignature()->getRequirements()) {
auto Kind = Req.getKind();

Type First = Req.getFirstType().subst(
M, subMap, SubstOptions());
Type Second = Req.getSecondType().subst(
M, subMap, SubstOptions());
Type First = Req.getFirstType().subst(subMap);
Type Second = Req.getSecondType().subst(subMap);

if (!First || !Second) {
// Substitution with interface type bases can only fail
// if a concrete type fails to conform to a protocol.
Expand Down Expand Up @@ -874,9 +873,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
assert(DC->isTypeContext());

// Get the substitutions from our base type.
auto subMap = CurrentType->getContextSubstitutions(DC);
auto *M = DC->getParentModule();
T = T.subst(M, subMap, SubstFlags::DesugarMemberTypes);
auto subMap = CurrentType->getContextSubstitutionMap(M, DC);
T = T.subst(subMap, SubstFlags::DesugarMemberTypes);
}

printType(T);
Expand Down Expand Up @@ -995,9 +994,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
Type OldType = CurrentType;
if (CurrentType && (Old != nullptr || Options.PrintAsMember)) {
if (auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
CurrentType = NTD->getDeclaredInterfaceType().subst(
Options.CurrentModule,
CurrentType->getContextSubstitutions(NTD->getDeclContext()));
auto Subs = CurrentType->getContextSubstitutionMap(
Options.CurrentModule, NTD->getDeclContext());
CurrentType = NTD->getDeclaredInterfaceType().subst(Subs);
}
}

Expand Down Expand Up @@ -1268,17 +1267,19 @@ void PrintAST::printSingleDepthOfGenericSignature(
bool printParams = (flags & PrintParams);
bool printRequirements = (flags & PrintRequirements);

TypeSubstitutionMap subMap;
ModuleDecl *M = nullptr;

SubstitutionMap subMap;
if (CurrentType) {
if (!CurrentType->isExistentialType()) {
auto *DC = Current->getInnermostDeclContext()->getInnermostTypeContext();
subMap = CurrentType->getContextSubstitutions(DC);
M = DC->getParentModule();
auto *M = DC->getParentModule();
subMap = CurrentType->getContextSubstitutionMap(M, DC);
}
}

auto substParam = [&](Type param) -> Type {
return param.subst(subMap);
};

if (printParams) {
// Print the generic parameters.
Printer << "<";
Expand All @@ -1290,7 +1291,7 @@ void PrintAST::printSingleDepthOfGenericSignature(
Printer << ", ";

if (!subMap.empty()) {
if (auto argTy = Type(param).subst(M, subMap))
if (auto argTy = substParam(param))
printType(argTy);
else
printType(param);
Expand Down Expand Up @@ -1322,10 +1323,10 @@ void PrintAST::printSingleDepthOfGenericSignature(
}

if (!subMap.empty()) {
if (Type subFirst = first.subst(M, subMap))
if (Type subFirst = substParam(first))
first = subFirst;
if (second) {
if (Type subSecond = second.subst(M, subMap))
if (Type subSecond = substParam(second))
second = subSecond;
if (!(first->is<ArchetypeType>() || first->isTypeParameter()) &&
!(second->is<ArchetypeType>() || second->isTypeParameter()))
Expand Down
9 changes: 2 additions & 7 deletions lib/AST/GenericEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,15 +332,10 @@ Type GenericEnvironment::getSugaredType(Type type) const {

ArrayRef<Substitution>
GenericEnvironment::getForwardingSubstitutions() const {
auto lookupConformanceFn =
[&](CanType original, Type replacement, ProtocolType *protoType)
-> Optional<ProtocolConformanceRef> {
return ProtocolConformanceRef(protoType->getDecl());
};

SmallVector<Substitution, 4> result;
getGenericSignature()->getSubstitutions(QueryInterfaceTypeSubstitutions(this),
lookupConformanceFn, result);
MakeAbstractConformanceForGenericType(),
result);
return getGenericSignature()->getASTContext().AllocateCopy(result);
}

Expand Down
66 changes: 59 additions & 7 deletions lib/AST/GenericSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,62 @@ GenericSignature::getSubstitutionMap(ArrayRef<Substitution> subs,
assert(subs.empty() && "did not use all substitutions?!");
}

SubstitutionMap
GenericSignature::
getSubstitutionMap(TypeSubstitutionFn subs,
GenericSignature::LookupConformanceFn lookupConformance) const {
SubstitutionMap subMap;

// Enumerate all of the requirements that require substitution.
enumeratePairedRequirements([&](Type depTy, ArrayRef<Requirement> reqs) {
auto canTy = depTy->getCanonicalType();

// Compute the replacement type.
Type currentReplacement = depTy.subst(subs, lookupConformance,
SubstFlags::UseErrorType);
if (auto substTy = dyn_cast<SubstitutableType>(canTy))
subMap.addSubstitution(substTy, currentReplacement);

// Collect the conformances.
for (auto req: reqs) {
assert(req.getKind() == RequirementKind::Conformance);
auto protoType = req.getSecondType()->castTo<ProtocolType>();
if (auto conformance = lookupConformance(canTy,
currentReplacement,
protoType)) {
subMap.addConformance(canTy, *conformance);
}
}

return false;
});

for (auto reqt : getRequirements()) {
if (reqt.getKind() != RequirementKind::SameType)
continue;

auto first = reqt.getFirstType();
auto second = reqt.getSecondType();

if (!first->isTypeParameter() || !second->isTypeParameter())
continue;

if (auto *firstMemTy = first->getAs<DependentMemberType>()) {
subMap.addParent(second->getCanonicalType(),
firstMemTy->getBase()->getCanonicalType(),
firstMemTy->getAssocType());
}

if (auto *secondMemTy = second->getAs<DependentMemberType>()) {
subMap.addParent(first->getCanonicalType(),
secondMemTy->getBase()->getCanonicalType(),
secondMemTy->getAssocType());
}
}

return subMap;
}

SmallVector<Type, 4> GenericSignature::getAllDependentTypes() const {
SmallVector<Type, 4> result;
enumeratePairedRequirements([&](Type type, ArrayRef<Requirement>) {
Expand Down Expand Up @@ -409,13 +465,9 @@ getSubstitutions(TypeSubstitutionFn subs,
void GenericSignature::
getSubstitutions(const SubstitutionMap &subMap,
SmallVectorImpl<Substitution> &result) const {
auto lookupConformanceFn =
[&](CanType original, Type replacement, ProtocolType *protoType)
-> Optional<ProtocolConformanceRef> {
return subMap.lookupConformance(original, protoType->getDecl());
};

getSubstitutions(subMap.getMap(), lookupConformanceFn, result);
getSubstitutions(subMap.getMap(),
LookUpConformanceInSubstitutionMap(subMap),
result);
}

bool GenericSignature::requiresClass(Type type, ModuleDecl &mod) {
Expand Down
8 changes: 4 additions & 4 deletions lib/AST/LookupVisibleDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,8 +732,8 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {

auto FoundSignature = VD->getOverloadSignature();
if (FoundSignature.InterfaceType && shouldSubst) {
auto subs = BaseTy->getMemberSubstitutions(VD);
if (auto CT = FoundSignature.InterfaceType.subst(M, subs, None))
auto subs = BaseTy->getMemberSubstitutionMap(M, VD);
if (auto CT = FoundSignature.InterfaceType.subst(subs))
FoundSignature.InterfaceType = CT->getCanonicalType();
}

Expand All @@ -748,8 +748,8 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {

auto OtherSignature = OtherVD->getOverloadSignature();
if (OtherSignature.InterfaceType && shouldSubst) {
auto subs = BaseTy->getMemberSubstitutions(OtherVD);
if (auto CT = OtherSignature.InterfaceType.subst(M, subs, None))
auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD);
if (auto CT = OtherSignature.InterfaceType.subst(subs))
OtherSignature.InterfaceType = CT->getCanonicalType();
}

Expand Down
27 changes: 2 additions & 25 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,31 +634,9 @@ TypeBase::gatherAllSubstitutions(ModuleDecl *module,
}
}

auto lookupConformanceFn =
[&](CanType original, Type replacement, ProtocolType *protoType)
-> Optional<ProtocolConformanceRef> {
auto *proto = protoType->getDecl();

// If the type is a type variable or is dependent, just fill in empty
// conformances.
if (replacement->isTypeVariableOrMember() ||
replacement->isTypeParameter())
return ProtocolConformanceRef(proto);

// Otherwise, try to find the conformance.
auto conforms = module->lookupConformance(replacement, proto, resolver);
if (conforms)
return *conforms;

// FIXME: Should we ever end up here?
// We should return None and let getSubstitutions handle the error
// if we do.
return ProtocolConformanceRef(proto);
};

SmallVector<Substitution, 4> result;
genericSig->getSubstitutions(substitutions,
lookupConformanceFn,
LookUpConformanceInModule(module),
result);

// Before recording substitutions, make sure we didn't end up doing it
Expand Down Expand Up @@ -762,9 +740,8 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol,
}

// Type variables have trivial conformances.
if (type->isTypeVariableOrMember()) {
if (type->isTypeVariableOrMember())
return ProtocolConformanceRef(protocol);
}

// UnresolvedType is a placeholder for an unknown type used when generating
// diagnostics. We consider it to conform to all protocols, since the
Expand Down
16 changes: 8 additions & 8 deletions lib/AST/SubstitutionMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ Optional<T> SubstitutionMap::forEachConformance(
return found;
}
} else {
auto sub = conformance.getConcrete()->getTypeWitnessSubstAndDecl(
auto sub = conformance.getConcrete()->getTypeWitnessSubstAndDecl(
protoAssocType, nullptr).first;
for (auto subConformance : sub.getConformances()) {
if (auto found = fn(subConformance))
return found;
}
for (auto subConformance : sub.getConformances()) {
if (auto found = fn(subConformance))
return found;
}
}
}

Expand Down Expand Up @@ -130,7 +130,8 @@ SubstitutionMap::lookupConformance(
CanType type, ProtocolDecl *proto,
llvm::SmallPtrSetImpl<CanType> *visitedParents) const {
// Local function to either record an abstract conformance or return a
// concrete conformance. This allows us to
// concrete conformance. This allows us to check multiple parents and
// find the most specific conformance that applies.
Optional<ProtocolConformanceRef> abstractConformance;
auto recordOrReturn = [&](ProtocolConformanceRef conformance)
-> Optional<ProtocolConformanceRef> {
Expand Down Expand Up @@ -232,8 +233,7 @@ SubstitutionMap::getOverrideSubstitutions(const ClassDecl *baseClass,
auto baseClassTy = derivedClassTy->getSuperclassForDecl(baseClass, resolver);

auto *M = baseClass->getParentModule();
auto subs = baseClassTy->gatherAllSubstitutions(M, resolver);
genericSig->getSubstitutionMap(subs, subMap);
subMap = baseClassTy->getContextSubstitutionMap(M, baseClass);

minDepth = genericSig->getGenericParams().back()->getDepth() + 1;
}
Expand Down
Loading