Files
swift-mirror/lib/AST/GenericEnvironment.cpp
Doug Gregor 66e20116f2 Extend ErrorType with an "original type" and use it to clean up substitution.
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.
2016-10-06 16:40:28 -07:00

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?!");
}