mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Mess with the way we do canonicalization for ProtocolCompositionTypes in a way
that doesn't violate canonical type invariants. It's still a little messy, but it's consistent. Fixes <rdar://problem/11886926>. Swift SVN r2368
This commit is contained in:
@@ -991,23 +991,18 @@ private:
|
||||
/// protocol, then the canonical type is that protocol type. Otherwise, it is
|
||||
/// a composition of the protocols in that list.
|
||||
class ProtocolCompositionType : public TypeBase, public llvm::FoldingSetNode {
|
||||
ASTContext &Ctx; // Note: Needed for canonicalization of the empty case.
|
||||
SourceLoc FirstLoc; // FIXME: Egregious hack due to lack of TypeLocs
|
||||
ArrayRef<Type> Protocols;
|
||||
|
||||
public:
|
||||
/// \brief Retrieve an instance of a protocol composition type with the
|
||||
/// given set of protocols.
|
||||
static ProtocolCompositionType *
|
||||
get(ASTContext &C, SourceLoc FirstLoc, ArrayRef<Type> Protocols);
|
||||
static Type get(ASTContext &C, SourceLoc FirstLoc, ArrayRef<Type> Protocols);
|
||||
|
||||
/// \brief Retrieve the source location where this type was first uttered.
|
||||
/// FIXME: This is a hackaround for the lack of TypeLocs.
|
||||
SourceLoc getFirstLoc() const { return FirstLoc; }
|
||||
|
||||
/// \brief Retrieve the AST context of this type.
|
||||
ASTContext &getASTContext() const { return Ctx; }
|
||||
|
||||
/// \brief Retrieve the set of protocols composed to create this type.
|
||||
ArrayRef<Type> getProtocols() const { return Protocols; }
|
||||
|
||||
@@ -1025,11 +1020,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
ProtocolCompositionType(ASTContext &Ctx, SourceLoc FirstLoc,
|
||||
static ProtocolCompositionType *build(ASTContext &C, SourceLoc FirstLoc,
|
||||
ArrayRef<Type> Protocols);
|
||||
|
||||
ProtocolCompositionType(ASTContext *Ctx, SourceLoc FirstLoc,
|
||||
ArrayRef<Type> Protocols)
|
||||
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/nullptr,
|
||||
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/Ctx,
|
||||
/*Unresolved=*/false),
|
||||
Ctx(Ctx), FirstLoc(FirstLoc), Protocols(Protocols) { }
|
||||
FirstLoc(FirstLoc), Protocols(Protocols) { }
|
||||
};
|
||||
|
||||
/// LValueType - An l-value is a handle to a physical object. The
|
||||
|
||||
@@ -240,8 +240,8 @@ IdentifierType *IdentifierType::getNew(ASTContext &C,
|
||||
}
|
||||
|
||||
ProtocolCompositionType *
|
||||
ProtocolCompositionType::get(ASTContext &C, SourceLoc FirstLoc,
|
||||
ArrayRef<Type> Protocols) {
|
||||
ProtocolCompositionType::build(ASTContext &C, SourceLoc FirstLoc,
|
||||
ArrayRef<Type> Protocols) {
|
||||
// Check to see if we've already seen this protocol composition before.
|
||||
void *InsertPos = 0;
|
||||
llvm::FoldingSetNodeID ID;
|
||||
@@ -249,10 +249,17 @@ ProtocolCompositionType::get(ASTContext &C, SourceLoc FirstLoc,
|
||||
if (ProtocolCompositionType *Result
|
||||
= C.Impl.ProtocolCompositionTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return Result;
|
||||
|
||||
|
||||
bool isCanonical = true;
|
||||
for (Type t : Protocols) {
|
||||
if (!t->isCanonical())
|
||||
isCanonical = false;
|
||||
}
|
||||
|
||||
// Create a new protocol composition type.
|
||||
ProtocolCompositionType *New = new (C) ProtocolCompositionType(C, FirstLoc,
|
||||
Protocols);
|
||||
ProtocolCompositionType *New =
|
||||
new (C) ProtocolCompositionType(isCanonical ? &C : nullptr, FirstLoc,
|
||||
C.AllocateCopy(Protocols));
|
||||
C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos);
|
||||
return New;
|
||||
}
|
||||
|
||||
@@ -435,44 +435,13 @@ CanType TypeBase::getCanonicalType() {
|
||||
break;
|
||||
}
|
||||
case TypeKind::ProtocolComposition: {
|
||||
// Collect all of the protocols composed together.
|
||||
auto PC = cast<ProtocolCompositionType>(this);
|
||||
SmallVector<ProtocolDecl *, 4> Protocols;
|
||||
addProtocols(this, Protocols);
|
||||
|
||||
// Minimize the set of protocols composed together.
|
||||
minimizeProtocols(Protocols);
|
||||
|
||||
// If one protocol remains, its nominal type is the canonical type.
|
||||
if (Protocols.size() == 1)
|
||||
Result = Protocols.front()->getDeclaredType();
|
||||
else {
|
||||
// Sort the set of protocols by module + name, to give a stable
|
||||
// ordering.
|
||||
// FIXME: Consider namespaces here as well.
|
||||
llvm::array_pod_sort(Protocols.begin(),Protocols.end(), compareProtocols);
|
||||
|
||||
// Form the set of canonical protocol types from the protocol
|
||||
// declarations, and use that to buid the canonical composition type.
|
||||
SmallVector<Type, 4> ProtocolTypes;
|
||||
std::transform(Protocols.begin(), Protocols.end(),
|
||||
std::back_inserter(ProtocolTypes),
|
||||
[](ProtocolDecl *Proto) {
|
||||
return Proto->getDeclaredType();
|
||||
});
|
||||
|
||||
Result = ProtocolCompositionType::get(
|
||||
PC->getASTContext(),
|
||||
PC->getFirstLoc(),
|
||||
PC->getASTContext().AllocateCopy(ProtocolTypes));
|
||||
|
||||
// We now know that the result type we computed is canonical; make it so.
|
||||
Result->CanonicalType = &PC->getASTContext();
|
||||
}
|
||||
|
||||
// If the result type we found was ourselves, we're done.
|
||||
if (this == Result)
|
||||
return CanType(Result);
|
||||
SmallVector<Type, 4> CanProtos;
|
||||
for (Type t : cast<ProtocolCompositionType>(this)->getProtocols())
|
||||
CanProtos.push_back(t->getCanonicalType());
|
||||
assert(!CanProtos.empty() && "Non-canonical empty composition?");
|
||||
ASTContext &C = CanProtos[0]->getASTContext();
|
||||
Type Composition = ProtocolCompositionType::get(C, SourceLoc(), CanProtos);
|
||||
Result = Composition.getPointer();
|
||||
break;
|
||||
}
|
||||
case TypeKind::MetaType: {
|
||||
@@ -715,6 +684,42 @@ BoundGenericType::setConformances(ArrayRef<unsigned> Offsets,
|
||||
AllConformances->Conformances = Ctx.AllocateCopy(Conformances);
|
||||
}
|
||||
|
||||
Type
|
||||
ProtocolCompositionType::get(ASTContext &C, SourceLoc FirstLoc,
|
||||
ArrayRef<Type> ProtocolTypes) {
|
||||
for (Type t : ProtocolTypes) {
|
||||
if (!t->isCanonical())
|
||||
return build(C, FirstLoc, ProtocolTypes);
|
||||
}
|
||||
|
||||
SmallVector<ProtocolDecl *, 4> Protocols;
|
||||
for (Type t : ProtocolTypes)
|
||||
addProtocols(t, Protocols);
|
||||
|
||||
// Minimize the set of protocols composed together.
|
||||
minimizeProtocols(Protocols);
|
||||
|
||||
// If one protocol remains, its nominal type is the canonical type.
|
||||
if (Protocols.size() == 1)
|
||||
return Protocols.front()->getDeclaredType();
|
||||
|
||||
// Sort the set of protocols by module + name, to give a stable
|
||||
// ordering.
|
||||
// FIXME: Consider namespaces here as well.
|
||||
llvm::array_pod_sort(Protocols.begin(), Protocols.end(), compareProtocols);
|
||||
|
||||
// Form the set of canonical protocol types from the protocol
|
||||
// declarations, and use that to buid the canonical composition type.
|
||||
SmallVector<Type, 4> CanProtocolTypes;
|
||||
std::transform(Protocols.begin(), Protocols.end(),
|
||||
std::back_inserter(CanProtocolTypes),
|
||||
[](ProtocolDecl *Proto) {
|
||||
return Proto->getDeclaredType();
|
||||
});
|
||||
|
||||
return build(C, SourceLoc(), CanProtocolTypes);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type Printing
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -302,8 +302,7 @@ bool Parser::parseTypeComposition(Type &Result, TypeLoc *&ResultLoc) {
|
||||
EndLoc = consumeStartingGreater();
|
||||
}
|
||||
|
||||
Result = ProtocolCompositionType::get(Context, ProtocolLoc,
|
||||
Context.AllocateCopy(Protocols));
|
||||
Result = ProtocolCompositionType::get(Context, ProtocolLoc, Protocols);
|
||||
ResultLoc = TypeLoc::get(Context, SourceRange(ProtocolLoc, EndLoc));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -247,8 +247,7 @@ collectArchetypeToExistentialSubstitutions(ASTContext &Context,
|
||||
std::back_inserter(ConformsTo),
|
||||
[](ProtocolDecl *P) { return P->getDeclaredType(); });
|
||||
Substitutions[Archetype]
|
||||
= ProtocolCompositionType::get(Context, SourceLoc(),
|
||||
Context.AllocateCopy(ConformsTo));
|
||||
= ProtocolCompositionType::get(Context, SourceLoc(), ConformsTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,8 +693,7 @@ Type TypeChecker::substType(Type T, TypeSubstitutionMap &Substitutions) {
|
||||
if (!AnyChanged)
|
||||
return T;
|
||||
|
||||
return ProtocolCompositionType::get(Context, PC->getFirstLoc(),
|
||||
Context.AllocateCopy(Protocols));
|
||||
return ProtocolCompositionType::get(Context, PC->getFirstLoc(), Protocols);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user