Files
swift-mirror/lib/AST/ExistentialGeneralization.cpp
Josh Soref 81d3ad76ac Spelling ast (#42463)
* spelling: accessor

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: accommodates

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: argument

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: associated

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: availability

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: available

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: belongs

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: bookkeeping

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: building

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: clazz

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: clonable

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: closure

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: concatenated

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: conformance

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: context

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: conversion

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: correspondence

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: declarations

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: declared

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: defining

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: delayed

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: dependency

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: deployed

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: descendants

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: diagnose

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: diagnostic

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: equitable

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: evaluation

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: exclusivity

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: existence

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: existential

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: explicit

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: expressed

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: for

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: foreign

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: function

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: identifier

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: implicit

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: indices

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: information

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: instance

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: interchangeable

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: interface

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: introduced

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: invalid

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: kind-in

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: least

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: library

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: location

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: namespace

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: necessary

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: nonexistent

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: not

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: number

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: obtains

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: occurs

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: opaque

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: overridden

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: parameter

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: precede

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: preceding

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: property

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: protocol

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: qualified

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: recognized

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: recursively

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: references

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: relaxing

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: represented

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: request

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: requirement

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: requirements

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: retrieve

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: returned

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: satisfied

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: satisfy

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: scanner

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: siblings

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: simplified

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: something

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: source

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: specializations

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: specially

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: statement

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: stripped

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: structure

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: substitution

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: the

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: transform

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: transformed

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: transitively

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: transparent

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: typecheck

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: unknown

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: unlabeled

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: unqualified

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: whether

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: with

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: scanner

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
2022-04-21 12:57:16 -07:00

285 lines
10 KiB
C++

//===--- ExistentialGeneralization.cpp - Shape generalization algorithm ---===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the existential type generalization algorithm,
// which is used in the ABI for existential types.
//
//===----------------------------------------------------------------------===//
#include "GenericSignatureBuilder.h"
#include "swift/AST/Types.h"
#include "swift/AST/CanTypeVisitor.h"
#include "llvm/ADT/DenseMap.h"
using namespace swift;
namespace {
/// A helper type for performing existential type generalization.
class Generalizer : public CanTypeVisitor<Generalizer, Type> {
friend CanTypeVisitor<Generalizer, Type>;
ASTContext &ctx;
llvm::DenseMap<CanType, Type> substTypes;
llvm::DenseMap<std::pair<CanType, ProtocolDecl*>,
ProtocolConformanceRef> substConformances;
Optional<GenericSignatureBuilder> sigBuilderStorage;
GenericSignatureBuilder &sigBuilder() {
if (!sigBuilderStorage)
sigBuilderStorage.emplace(ctx);
return *sigBuilderStorage;
}
public:
Generalizer(ASTContext &ctx) : ctx(ctx) {}
/// Given that the given type is not itself substitutable in whatever
/// position it appears in, generalize it.
Type generalizeStructure(CanType type) {
return visit(type);
}
SubstitutionMap getGeneralizationSubstitutions() {
// If we never introduced a generalization parameter, we're done.
if (!sigBuilderStorage) return SubstitutionMap();
// Finish the signature.
auto sig = std::move(*sigBuilderStorage).computeGenericSignature();
sigBuilderStorage.reset();
// TODO: minimize the signature by removing redundant generic
// parameters.
auto lookupParameter = [&](SubstitutableType *type) {
auto it = substTypes.find(CanType(type));
assert(it != substTypes.end());
return it->second;
};
auto lookupConformance = [&](CanType dependentType,
Type conformingReplacementType,
ProtocolDecl *conformedProtocol) {
auto it = substConformances.find({dependentType, conformedProtocol});
assert(it != substConformances.end());
return it->second;
};
return SubstitutionMap::get(sig, lookupParameter, lookupConformance);
}
private:
Type visitProtocolType(CanProtocolType type) {
// Simple protocol types have no sub-structure.
assert(!type.getParent());
return type;
}
Type visitParameterizedProtocolType(CanParameterizedProtocolType origType) {
// Generalize the argument types of parameterized protocols,
// but don't generalize the base type.
auto origArgs = origType.getArgs();
SmallVector<Type, 4> newArgs;
newArgs.reserve(origArgs.size());
for (auto origArg: origArgs) {
newArgs.push_back(generalizeComponentType(origArg));
}
return ParameterizedProtocolType::get(ctx, origType->getBaseType(),
newArgs);
}
Type visitProtocolCompositionType(CanProtocolCompositionType origType) {
// The member types of protocol compositions are not substitutable,
// including class constraints. Generalize them individually,
// preserving structure.
auto origMembers = origType.getMembers();
SmallVector<Type, 4> newMembers;
newMembers.reserve(origMembers.size());
for (auto origMember: origMembers) {
newMembers.push_back(generalizeStructure(origMember));
}
return ProtocolCompositionType::get(ctx, newMembers,
origType->hasExplicitAnyObject());
}
// Generalize the type arguments of nominal types.
Type visitBoundGenericType(CanBoundGenericType origType) {
return generalizeGenericArguments(origType->getDecl(), origType);
}
Type visitNominalType(CanNominalType origType) {
auto decl = origType->getDecl();
if (decl->isGenericContext())
return generalizeGenericArguments(decl, origType);
return origType;
}
// Preserve existential structure.
Type visitExistentialType(CanExistentialType origType) {
return ExistentialType::get(
generalizeStructure(origType.getConstraintType()));
}
Type visitExistentialMetatypeType(CanExistentialMetatypeType origType) {
assert(!origType->hasRepresentation());
return ExistentialMetatypeType::get(
generalizeStructure(origType.getInstanceType()));
}
// These types can be generalized by a recursive transform of
// their component types; we don't need to exclude anything or
// handle conformances.
#define GENERALIZE_COMPONENTS(ID) \
Type visit##ID##Type(Can##ID##Type origType) { \
return generalizeComponentTypes(origType); \
}
GENERALIZE_COMPONENTS(Function)
GENERALIZE_COMPONENTS(Metatype)
GENERALIZE_COMPONENTS(Tuple)
#undef GENERALIZE_COMPONENTS
// These types can never contain component types with abstract
// constraints, so generalizeComponentType should always substitute
// them out.
#define NO_PRESERVABLE_STRUCTURE(ID) \
Type visit##ID##Type(Can##ID##Type origType) { \
llvm_unreachable(#ID "Type has no structure to preserve"); \
}
NO_PRESERVABLE_STRUCTURE(Archetype)
NO_PRESERVABLE_STRUCTURE(Builtin)
NO_PRESERVABLE_STRUCTURE(DependentMember)
NO_PRESERVABLE_STRUCTURE(GenericTypeParam)
NO_PRESERVABLE_STRUCTURE(Module)
NO_PRESERVABLE_STRUCTURE(Pack)
NO_PRESERVABLE_STRUCTURE(PackExpansion)
#undef NO_PRESERVABLE_STRUCTURE
// These types simply shouldn't appear in types that we generalize at all.
#define INVALID_TO_GENERALIZE(ID) \
Type visit##ID##Type(Can##ID##Type origType) { \
llvm_unreachable(#ID "type should not be found by generalization"); \
}
INVALID_TO_GENERALIZE(DynamicSelf)
INVALID_TO_GENERALIZE(Error)
INVALID_TO_GENERALIZE(GenericFunction)
INVALID_TO_GENERALIZE(InOut)
INVALID_TO_GENERALIZE(LValue)
INVALID_TO_GENERALIZE(ReferenceStorage)
INVALID_TO_GENERALIZE(SILBlockStorage)
INVALID_TO_GENERALIZE(SILBox)
INVALID_TO_GENERALIZE(SILFunction)
INVALID_TO_GENERALIZE(SILToken)
#undef INVALID_TO_GENERALIZE
/// Generalize the generic arguments of the given generic type.s
Type generalizeGenericArguments(NominalTypeDecl *decl, CanType type) {
assert(decl->isGenericContext());
auto origSubs = type->getContextSubstitutionMap(decl->getModuleContext(),
decl);
// Generalize all of the arguments.
auto origArgs = origSubs.getReplacementTypes();
SmallVector<Type, 4> newArgs;
for (auto origArg: origArgs) {
newArgs.push_back(generalizeComponentType(CanType(origArg)));
}
// Generalize all of the conformances.
// TODO: for abstract requirements, we might not generalize all
// arguments, and we may need to leave corresponding conformances
// concrete.
SmallVector<ProtocolConformanceRef, 4> newConformances;
auto origConformances = origSubs.getConformances();
for (auto origConformance: origConformances) {
newConformances.push_back(
ProtocolConformanceRef(origConformance.getRequirement()));
}
auto origSig = origSubs.getGenericSignature();
auto newSubs = SubstitutionMap::get(origSig, newArgs, newConformances);
// Add any conformance requirements to the generic signature and
// remember the conformances we generalized.
if (!origConformances.empty()) {
size_t i = 0;
for (auto &origReq: origSig.getRequirements()) {
if (origReq.getKind() != RequirementKind::Conformance) continue;
auto origConformance = origConformances[i++];
auto optNewReq = origReq.subst(newSubs);
assert(optNewReq && "generalization substitution failed");
auto &newReq = *optNewReq;
auto source = GenericSignatureBuilder::
FloatingRequirementSource::forInferred(SourceLoc());
sigBuilder().addRequirement(newReq, source, nullptr);
substConformances.insert({{newReq.getFirstType()->getCanonicalType(),
newReq.getProtocolDecl()},
origConformance});
}
}
// Build the new type.
return decl->getDeclaredInterfaceType().subst(newSubs);
}
/// Generalize the given type by preserving its top-level structure
/// but generalizing its component types.
Type generalizeComponentTypes(CanType type) {
return type.transformRec([&](TypeBase *componentType) -> Optional<Type> {
// Ignore the top level.
if (componentType == type.getPointer())
return None;
return generalizeComponentType(CanType(componentType));
});
}
Type generalizeComponentType(CanType origArg) {
// TODO: Abstract constraints (some P) introduce *existential*
// component types, which are not substitutable. Therefore, types
// containing them must be generalized preserving that structure
// rather than wholly substituted. They can appear in arbitrary
// positions, including within tuple, function, and metatype types,
// so we'll need to add cases for those to generalizeStructure
// above.
// Create a new generalization type parameter and record the
// substitution.
auto newParam = GenericTypeParamType::get(/*sequence*/ false,
/*depth*/ 0,
/*index*/ substTypes.size(),
ctx);
sigBuilder().addGenericParameter(newParam);
substTypes.insert({CanType(newParam), origArg});
return newParam;
}
};
} // end anonymous namespace
ExistentialTypeGeneralization
ExistentialTypeGeneralization::get(Type rawType) {
assert(rawType->isExistentialType());
assert(!rawType->hasTypeParameter());
// Canonicalize. We need to generalize the canonical shape of the
// type or else generalization parameters won't match up.
CanType type = rawType->getCanonicalType();
Generalizer generalizer(type->getASTContext());
Type shape = generalizer.generalizeStructure(type);
auto subs = generalizer.getGeneralizationSubstitutions();
return {shape, subs};
}