mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Type::subst()'s "IgnoreMissing" option was fairly unprincipled, dropping unsubstituted types into the resulting AST without any indication whatsoever that anything went wrong. Replace this notion with a new form of ErrorType that explicitly tracks which substituted type caused the problem. It's still an ErrorType, but it prints like the substituted type (which is important for code completion) and allows us to step back to the substituted type if needed (which is used by associated type inference). Then, allow Type::subst(), when the new UseErrorTypes flag is passed, to form partially-substituted types that contain errors, which both code completion and associated type inference relied on. Over time, I hope we can use error-types-with-original-types more often to eliminate "<<error type>>" from diagnostics and teach Type::subst() never to return a "null" type. Clients can check "hasError()" to deal with failure cases rather than checking null.
155 lines
5.6 KiB
C++
155 lines
5.6 KiB
C++
//===--- 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(
|
|
TypeSubstitutionMap interfaceToArchetypeMap) {
|
|
|
|
assert(!interfaceToArchetypeMap.empty());
|
|
|
|
// 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;
|
|
}
|
|
|
|
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?!");
|
|
}
|