blob: 74ec859954e05b1d956a9f23a3c9197be76a1603 [file] [log] [blame]
//===--- GenericEnvironment.cpp - GenericEnvironment 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 GenericEnvironment class.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTContext.h"
#include "swift/AST/GenericEnvironment.h"
using namespace swift;
GenericEnvironment::GenericEnvironment(
ArrayRef<GenericTypeParamType *> genericParamTypes,
TypeSubstitutionMap interfaceToArchetypeMap) {
assert(!interfaceToArchetypeMap.empty());
for (auto *paramTy : genericParamTypes)
GenericParams.push_back(paramTy);
// Build a mapping in both directions, making sure to canonicalize the
// interface type where it is used as a key, so that substitution can
// find them, and to preserve sugar otherwise, so that
// mapTypeOutOfContext() produces a human-readable type.
for (auto entry : interfaceToArchetypeMap) {
// We're going to pass InterfaceToArchetypeMap to Type::subst(), which
// expects the keys to be canonical, otherwise it won't be able to
// find them.
auto canParamTy = cast<GenericTypeParamType>(entry.first->getCanonicalType());
auto contextTy = entry.second;
auto result = InterfaceToArchetypeMap.insert(
std::make_pair(canParamTy, contextTy));
assert(result.second && "duplicate generic parameters in environment");
// If we mapped the generic parameter to an archetype, add it to the
// reverse mapping.
if (auto *archetypeTy = entry.second->getAs<ArchetypeType>())
ArchetypeToInterfaceMap[archetypeTy] = entry.first;
// FIXME: If multiple generic parameters map to the same archetype,
// the reverse mapping order is not deterministic.
}
}
void *GenericEnvironment::operator new(size_t bytes, const ASTContext &ctx) {
return ctx.Allocate(bytes, alignof(GenericEnvironment), AllocationArena::Permanent);
}
Type GenericEnvironment::mapTypeOutOfContext(ModuleDecl *M, Type type) const {
type = type.subst(M, ArchetypeToInterfaceMap, SubstFlags::AllowLoweredTypes);
assert(!type->hasArchetype() && "not fully substituted");
return type;
}
Type GenericEnvironment::mapTypeIntoContext(ModuleDecl *M, Type type) const {
type = type.subst(M, InterfaceToArchetypeMap, SubstFlags::AllowLoweredTypes);
assert((!type->hasTypeParameter() || type->hasError()) &&
"not fully substituted");
return type;
}
Type GenericEnvironment::mapTypeIntoContext(GenericTypeParamType *type) const {
auto canTy = type->getCanonicalType();
auto found = InterfaceToArchetypeMap.find(canTy.getPointer());
assert(found != InterfaceToArchetypeMap.end() &&
"missing generic parameter");
return found->second;
}
GenericTypeParamType *GenericEnvironment::getSugaredType(
GenericTypeParamType *type) const {
for (auto *sugaredType : GenericParams)
if (sugaredType->isEqual(type))
return sugaredType;
llvm_unreachable("missing generic parameter");
}
ArrayRef<Substitution>
GenericEnvironment::getForwardingSubstitutions(
ModuleDecl *M, GenericSignature *sig) const {
auto lookupConformanceFn =
[&](CanType original, Type replacement, ProtocolType *protoType)
-> ProtocolConformanceRef {
return ProtocolConformanceRef(protoType->getDecl());
};
SmallVector<Substitution, 4> result;
sig->getSubstitutions(*M, InterfaceToArchetypeMap,
lookupConformanceFn, result);
return sig->getASTContext().AllocateCopy(result);
}
SubstitutionMap GenericEnvironment::
getSubstitutionMap(ModuleDecl *mod,
GenericSignature *sig,
ArrayRef<Substitution> subs) const {
SubstitutionMap result;
getSubstitutionMap(mod, sig, subs, result);
return result;
}
void GenericEnvironment::
getSubstitutionMap(ModuleDecl *mod,
GenericSignature *sig,
ArrayRef<Substitution> subs,
SubstitutionMap &result) const {
for (auto depTy : sig->getAllDependentTypes()) {
// Map the interface type to a context type.
auto contextTy = depTy.subst(mod, InterfaceToArchetypeMap, SubstOptions());
auto *archetype = contextTy->castTo<ArchetypeType>();
auto sub = subs.front();
subs = subs.slice(1);
// Record the replacement type and its conformances.
result.addSubstitution(CanType(archetype), sub.getReplacement());
result.addConformances(CanType(archetype), sub.getConformances());
}
for (auto reqt : sig->getRequirements()) {
if (reqt.getKind() != RequirementKind::SameType)
continue;
auto first = reqt.getFirstType()->getAs<DependentMemberType>();
auto second = reqt.getSecondType()->getAs<DependentMemberType>();
if (!first || !second)
continue;
auto archetype = mapTypeIntoContext(mod, first)->getAs<ArchetypeType>();
if (!archetype)
continue;
auto firstBase = first->getBase();
auto secondBase = second->getBase();
auto firstBaseArchetype = mapTypeIntoContext(mod, firstBase)->getAs<ArchetypeType>();
auto secondBaseArchetype = mapTypeIntoContext(mod, secondBase)->getAs<ArchetypeType>();
if (!firstBaseArchetype || !secondBaseArchetype)
continue;
if (archetype->getParent() != firstBaseArchetype)
result.addParent(CanType(archetype),
CanType(firstBaseArchetype),
first->getAssocType());
if (archetype->getParent() != secondBaseArchetype)
result.addParent(CanType(archetype),
CanType(secondBaseArchetype),
second->getAssocType());
}
assert(subs.empty() && "did not use all substitutions?!");
}