blob: b8f1ad387dbf559bec0e9874ab136ebaac2b6f1b [file] [log] [blame]
//===--- GenericSignature.cpp - Generic Signature AST ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the GenericSignature class.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/GenericSignature.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/Types.h"
using namespace swift;
GenericSignature::GenericSignature(ArrayRef<GenericTypeParamType *> params,
ArrayRef<Requirement> requirements,
bool isKnownCanonical)
: NumGenericParams(params.size()), NumRequirements(requirements.size()),
CanonicalSignatureOrASTContext()
{
auto paramsBuffer = getGenericParamsBuffer();
for (unsigned i = 0; i < NumGenericParams; ++i) {
paramsBuffer[i] = params[i];
}
auto reqtsBuffer = getRequirementsBuffer();
for (unsigned i = 0; i < NumRequirements; ++i) {
reqtsBuffer[i] = requirements[i];
}
if (isKnownCanonical)
CanonicalSignatureOrASTContext = &getASTContext(params, requirements);
}
ArrayRef<GenericTypeParamType *>
GenericSignature::getInnermostGenericParams() const {
auto params = getGenericParams();
// Find the point at which the depth changes.
unsigned depth = params.back()->getDepth();
for (unsigned n = params.size(); n > 0; --n) {
if (params[n-1]->getDepth() != depth) {
return params.slice(n);
}
}
// All parameters are at the same depth.
return params;
}
ASTContext &GenericSignature::getASTContext(
ArrayRef<swift::GenericTypeParamType *> params,
ArrayRef<swift::Requirement> requirements) {
// The params and requirements cannot both be empty.
if (!params.empty())
return params.front()->getASTContext();
else
return requirements.front().getFirstType()->getASTContext();
}
ArchetypeBuilder *GenericSignature::getArchetypeBuilder(ModuleDecl &mod) {
// The archetype builder is associated with the canonical signature.
if (!isCanonical())
return getCanonicalSignature()->getArchetypeBuilder(mod);
// Archetype builders are stored on the ASTContext.
return getASTContext().getOrCreateArchetypeBuilder(CanGenericSignature(this),
&mod);
}
bool GenericSignature::isCanonical() const {
if (CanonicalSignatureOrASTContext.is<ASTContext*>()) return true;
return getCanonicalSignature() == this;
}
CanGenericSignature GenericSignature::getCanonical(
ArrayRef<GenericTypeParamType *> params,
ArrayRef<Requirement> requirements) {
// Canonicalize the parameters and requirements.
SmallVector<GenericTypeParamType*, 8> canonicalParams;
canonicalParams.reserve(params.size());
for (auto param : params) {
canonicalParams.push_back(cast<GenericTypeParamType>(param->getCanonicalType()));
}
SmallVector<Requirement, 8> canonicalRequirements;
canonicalRequirements.reserve(requirements.size());
for (auto &reqt : requirements) {
canonicalRequirements.push_back(Requirement(reqt.getKind(),
reqt.getFirstType()->getCanonicalType(),
reqt.getSecondType().getCanonicalTypeOrNull()));
}
auto canSig = get(canonicalParams, canonicalRequirements,
/*isKnownCanonical=*/true);
return CanGenericSignature(canSig);
}
CanGenericSignature
GenericSignature::getCanonicalSignature() const {
// If we haven't computed the canonical signature yet, do so now.
if (CanonicalSignatureOrASTContext.isNull()) {
// Compute the canonical signature.
CanGenericSignature canSig = getCanonical(getGenericParams(),
getRequirements());
// Record either the canonical signature or an indication that
// this is the canonical signature.
if (canSig != this)
CanonicalSignatureOrASTContext = canSig;
else
CanonicalSignatureOrASTContext = &getGenericParams()[0]->getASTContext();
// Return the canonical signature.
return canSig;
}
// A stored ASTContext indicates that this is the canonical
// signature.
if (CanonicalSignatureOrASTContext.is<ASTContext*>())
// TODO: CanGenericSignature should be const-correct.
return CanGenericSignature(const_cast<GenericSignature*>(this));
// Otherwise, return the stored canonical signature.
return CanGenericSignature(
CanonicalSignatureOrASTContext.get<GenericSignature*>());
}
ASTContext &GenericSignature::getASTContext() const {
// Canonical signatures store the ASTContext directly.
if (auto ctx = CanonicalSignatureOrASTContext.dyn_cast<ASTContext *>())
return *ctx;
// For everything else, just get it from the generic parameter.
return getASTContext(getGenericParams(), getRequirements());
}
SubstitutionMap
GenericSignature::getSubstitutionMap(ArrayRef<Substitution> subs) const {
SubstitutionMap result;
getSubstitutionMap(subs, result);
return result;
}
void
GenericSignature::getSubstitutionMap(ArrayRef<Substitution> subs,
SubstitutionMap &result) const {
// An empty parameter list gives an empty map.
if (subs.empty())
assert(getGenericParams().empty());
for (auto depTy : getAllDependentTypes()) {
auto sub = subs.front();
subs = subs.slice(1);
auto canTy = depTy->getCanonicalType();
result.addSubstitution(canTy, sub.getReplacement());
result.addConformances(canTy, sub.getConformances());
}
// TODO: same-type constraints
assert(subs.empty() && "did not use all substitutions?!");
}
void GenericSignature::
getSubstitutions(ModuleDecl &mod,
const TypeSubstitutionMap &subs,
GenericSignature::LookupConformanceFn lookupConformance,
SmallVectorImpl<Substitution> &result) const {
auto &ctx = getASTContext();
Type currentReplacement;
SmallVector<ProtocolConformanceRef, 4> currentConformances;
for (const auto &req : getRequirements()) {
auto depTy = req.getFirstType()->getCanonicalType();
switch (req.getKind()) {
case RequirementKind::Conformance: {
// Get the conformance and record it.
auto protoType = req.getSecondType()->castTo<ProtocolType>();
currentConformances.push_back(
lookupConformance(depTy, currentReplacement, protoType));
break;
}
case RequirementKind::Superclass:
// Superclass requirements aren't recorded in substitutions.
break;
case RequirementKind::SameType:
// Same-type requirements aren't recorded in substitutions.
break;
case RequirementKind::WitnessMarker:
// Flush the current conformances.
if (currentReplacement) {
result.push_back({
currentReplacement,
ctx.AllocateCopy(currentConformances)
});
currentConformances.clear();
}
// Each witness marker starts a new substitution.
currentReplacement = req.getFirstType().subst(&mod, subs);
if (!currentReplacement)
currentReplacement = ErrorType::get(req.getFirstType());
break;
}
}
// Flush the final conformances.
if (currentReplacement) {
result.push_back({
currentReplacement,
ctx.AllocateCopy(currentConformances),
});
currentConformances.clear();
}
}
void GenericSignature::
getSubstitutions(ModuleDecl &mod,
const SubstitutionMap &subMap,
SmallVectorImpl<Substitution> &result) const {
auto lookupConformanceFn =
[&](CanType original, Type replacement, ProtocolType *protoType)
-> ProtocolConformanceRef {
return *subMap.lookupConformance(original, protoType->getDecl());
};
getSubstitutions(mod, subMap.getMap(), lookupConformanceFn, result);
}
bool GenericSignature::requiresClass(Type type, ModuleDecl &mod) {
if (!type->isTypeParameter()) return false;
auto &builder = *getArchetypeBuilder(mod);
auto pa = builder.resolveArchetype(type);
if (!pa) return false;
pa = pa->getRepresentative();
// If this type was mapped to a concrete type, then there is no
// requirement.
if (pa->isConcreteType()) return false;
// If there is a superclass bound, then obviously it must be a class.
if (pa->getSuperclass()) return true;
// If any of the protocols are class-bound, then it must be a class.
for (auto proto : pa->getConformsTo()) {
if (proto.first->requiresClass()) return true;
}
return false;
}
/// Determine the superclass bound on the given dependent type.
Type GenericSignature::getSuperclassBound(Type type, ModuleDecl &mod) {
if (!type->isTypeParameter()) return nullptr;
auto &builder = *getArchetypeBuilder(mod);
auto pa = builder.resolveArchetype(type);
if (!pa) return nullptr;
pa = pa->getRepresentative();
// If this type was mapped to a concrete type, then there is no
// requirement.
if (pa->isConcreteType()) return nullptr;
// Retrieve the superclass bound.
return pa->getSuperclass();
}
/// Determine the set of protocols to which the given dependent type
/// must conform.
SmallVector<ProtocolDecl *, 2> GenericSignature::getConformsTo(Type type,
ModuleDecl &mod) {
if (!type->isTypeParameter()) return { };
auto &builder = *getArchetypeBuilder(mod);
auto pa = builder.resolveArchetype(type);
if (!pa) return { };
pa = pa->getRepresentative();
// If this type was mapped to a concrete type, then there are no
// requirements.
if (pa->isConcreteType()) return { };
// Retrieve the protocols to which this type conforms.
SmallVector<ProtocolDecl *, 2> result;
for (auto proto : pa->getConformsTo())
result.push_back(proto.first);
// Canonicalize the resulting set of protocols.
ProtocolType::canonicalizeProtocols(result);
return result;
}
/// Determine whether the given dependent type is equal to a concrete type.
bool GenericSignature::isConcreteType(Type type, ModuleDecl &mod) {
return bool(getConcreteType(type, mod));
}
/// Return the concrete type that the given dependent type is constrained to,
/// or the null Type if it is not the subject of a concrete same-type
/// constraint.
Type GenericSignature::getConcreteType(Type type, ModuleDecl &mod) {
if (!type->isTypeParameter()) return Type();
auto &builder = *getArchetypeBuilder(mod);
auto pa = builder.resolveArchetype(type);
if (!pa) return Type();
pa = pa->getRepresentative();
if (!pa->isConcreteType()) return Type();
return pa->getConcreteType();
}
Type GenericSignature::getRepresentative(Type type, ModuleDecl &mod) {
assert(type->isTypeParameter());
auto &builder = *getArchetypeBuilder(mod);
auto pa = builder.resolveArchetype(type);
assert(pa && "not a valid dependent type of this signature?");
auto rep = pa->getRepresentative();
if (rep->isConcreteType()) return rep->getConcreteType();
if (pa == rep) {
assert(rep->getDependentType(builder, /*allowUnresolved*/ false)
->getCanonicalType() == type->getCanonicalType());
return type;
}
return rep->getDependentType(builder, /*allowUnresolved*/ false);
}
bool GenericSignature::areSameTypeParameterInContext(Type type1, Type type2,
ModuleDecl &mod) {
assert(type1->isTypeParameter());
assert(type2->isTypeParameter());
if (type1.getPointer() == type2.getPointer())
return true;
auto &builder = *getArchetypeBuilder(mod);
auto pa1 = builder.resolveArchetype(type1);
assert(pa1 && "not a valid dependent type of this signature?");
pa1 = pa1->getRepresentative();
assert(!pa1->isConcreteType());
auto pa2 = builder.resolveArchetype(type2);
assert(pa2 && "not a valid dependent type of this signature?");
pa2 = pa2->getRepresentative();
assert(!pa2->isConcreteType());
return pa1 == pa2;
}
bool GenericSignature::isCanonicalTypeInContext(Type type, ModuleDecl &mod) {
// If the type isn't independently canonical, it's certainly not canonical
// in this context.
if (!type->isCanonical())
return false;
// All the contextual canonicality rules apply to type parameters, so if the
// type doesn't involve any type parameters, it's already canonical.
if (!type->hasTypeParameter())
return true;
auto &builder = *getArchetypeBuilder(mod);
// Look for non-canonical type parameters.
return !type.findIf([&](Type component) -> bool {
if (!component->isTypeParameter()) return false;
auto pa = builder.resolveArchetype(component);
if (!pa) return false;
auto rep = pa->getArchetypeAnchor();
return (rep->isConcreteType() || pa != rep);
});
}
CanType GenericSignature::getCanonicalTypeInContext(Type type, ModuleDecl &mod) {
type = type->getCanonicalType();
// All the contextual canonicality rules apply to type parameters, so if the
// type doesn't involve any type parameters, it's already canonical.
if (!type->hasTypeParameter())
return CanType(type);
auto &builder = *getArchetypeBuilder(mod);
// Replace non-canonical type parameters.
type = type.transform([&](Type component) -> Type {
if (!component->isTypeParameter()) return component;
// Resolve the potential archetype. This can be null in nested generic
// types, which we can't immediately canonicalize.
auto pa = builder.resolveArchetype(component);
if (!pa) return component;
auto rep = pa->getArchetypeAnchor();
if (rep->isConcreteType()) {
return getCanonicalTypeInContext(rep->getConcreteType(), mod);
} else {
return rep->getDependentType(builder, /*allowUnresolved*/ false);
}
});
auto result = type->getCanonicalType();
assert(isCanonicalTypeInContext(result, mod));
return result;
}