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:
Eli Friedman
2012-07-18 01:31:40 +00:00
parent 29b3994cca
commit 6a4098b102
6 changed files with 65 additions and 58 deletions

View File

@@ -991,23 +991,18 @@ private:
/// protocol, then the canonical type is that protocol type. Otherwise, it is /// protocol, then the canonical type is that protocol type. Otherwise, it is
/// a composition of the protocols in that list. /// a composition of the protocols in that list.
class ProtocolCompositionType : public TypeBase, public llvm::FoldingSetNode { 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 SourceLoc FirstLoc; // FIXME: Egregious hack due to lack of TypeLocs
ArrayRef<Type> Protocols; ArrayRef<Type> Protocols;
public: public:
/// \brief Retrieve an instance of a protocol composition type with the /// \brief Retrieve an instance of a protocol composition type with the
/// given set of protocols. /// given set of protocols.
static ProtocolCompositionType * static Type get(ASTContext &C, SourceLoc FirstLoc, ArrayRef<Type> Protocols);
get(ASTContext &C, SourceLoc FirstLoc, ArrayRef<Type> Protocols);
/// \brief Retrieve the source location where this type was first uttered. /// \brief Retrieve the source location where this type was first uttered.
/// FIXME: This is a hackaround for the lack of TypeLocs. /// FIXME: This is a hackaround for the lack of TypeLocs.
SourceLoc getFirstLoc() const { return FirstLoc; } 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. /// \brief Retrieve the set of protocols composed to create this type.
ArrayRef<Type> getProtocols() const { return Protocols; } ArrayRef<Type> getProtocols() const { return Protocols; }
@@ -1025,11 +1020,14 @@ public:
} }
private: private:
ProtocolCompositionType(ASTContext &Ctx, SourceLoc FirstLoc, static ProtocolCompositionType *build(ASTContext &C, SourceLoc FirstLoc,
ArrayRef<Type> Protocols);
ProtocolCompositionType(ASTContext *Ctx, SourceLoc FirstLoc,
ArrayRef<Type> Protocols) ArrayRef<Type> Protocols)
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/nullptr, : TypeBase(TypeKind::ProtocolComposition, /*Context=*/Ctx,
/*Unresolved=*/false), /*Unresolved=*/false),
Ctx(Ctx), FirstLoc(FirstLoc), Protocols(Protocols) { } FirstLoc(FirstLoc), Protocols(Protocols) { }
}; };
/// LValueType - An l-value is a handle to a physical object. The /// LValueType - An l-value is a handle to a physical object. The

View File

@@ -240,7 +240,7 @@ IdentifierType *IdentifierType::getNew(ASTContext &C,
} }
ProtocolCompositionType * ProtocolCompositionType *
ProtocolCompositionType::get(ASTContext &C, SourceLoc FirstLoc, ProtocolCompositionType::build(ASTContext &C, SourceLoc FirstLoc,
ArrayRef<Type> Protocols) { ArrayRef<Type> Protocols) {
// Check to see if we've already seen this protocol composition before. // Check to see if we've already seen this protocol composition before.
void *InsertPos = 0; void *InsertPos = 0;
@@ -250,9 +250,16 @@ ProtocolCompositionType::get(ASTContext &C, SourceLoc FirstLoc,
= C.Impl.ProtocolCompositionTypes.FindNodeOrInsertPos(ID, InsertPos)) = C.Impl.ProtocolCompositionTypes.FindNodeOrInsertPos(ID, InsertPos))
return Result; return Result;
bool isCanonical = true;
for (Type t : Protocols) {
if (!t->isCanonical())
isCanonical = false;
}
// Create a new protocol composition type. // Create a new protocol composition type.
ProtocolCompositionType *New = new (C) ProtocolCompositionType(C, FirstLoc, ProtocolCompositionType *New =
Protocols); new (C) ProtocolCompositionType(isCanonical ? &C : nullptr, FirstLoc,
C.AllocateCopy(Protocols));
C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos); C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos);
return New; return New;
} }

View File

@@ -435,44 +435,13 @@ CanType TypeBase::getCanonicalType() {
break; break;
} }
case TypeKind::ProtocolComposition: { case TypeKind::ProtocolComposition: {
// Collect all of the protocols composed together. SmallVector<Type, 4> CanProtos;
auto PC = cast<ProtocolCompositionType>(this); for (Type t : cast<ProtocolCompositionType>(this)->getProtocols())
SmallVector<ProtocolDecl *, 4> Protocols; CanProtos.push_back(t->getCanonicalType());
addProtocols(this, Protocols); assert(!CanProtos.empty() && "Non-canonical empty composition?");
ASTContext &C = CanProtos[0]->getASTContext();
// Minimize the set of protocols composed together. Type Composition = ProtocolCompositionType::get(C, SourceLoc(), CanProtos);
minimizeProtocols(Protocols); Result = Composition.getPointer();
// 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);
break; break;
} }
case TypeKind::MetaType: { case TypeKind::MetaType: {
@@ -715,6 +684,42 @@ BoundGenericType::setConformances(ArrayRef<unsigned> Offsets,
AllConformances->Conformances = Ctx.AllocateCopy(Conformances); 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 // Type Printing
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@@ -302,8 +302,7 @@ bool Parser::parseTypeComposition(Type &Result, TypeLoc *&ResultLoc) {
EndLoc = consumeStartingGreater(); EndLoc = consumeStartingGreater();
} }
Result = ProtocolCompositionType::get(Context, ProtocolLoc, Result = ProtocolCompositionType::get(Context, ProtocolLoc, Protocols);
Context.AllocateCopy(Protocols));
ResultLoc = TypeLoc::get(Context, SourceRange(ProtocolLoc, EndLoc)); ResultLoc = TypeLoc::get(Context, SourceRange(ProtocolLoc, EndLoc));
return false; return false;
} }

View File

@@ -247,8 +247,7 @@ collectArchetypeToExistentialSubstitutions(ASTContext &Context,
std::back_inserter(ConformsTo), std::back_inserter(ConformsTo),
[](ProtocolDecl *P) { return P->getDeclaredType(); }); [](ProtocolDecl *P) { return P->getDeclaredType(); });
Substitutions[Archetype] Substitutions[Archetype]
= ProtocolCompositionType::get(Context, SourceLoc(), = ProtocolCompositionType::get(Context, SourceLoc(), ConformsTo);
Context.AllocateCopy(ConformsTo));
} }
} }
} }

View File

@@ -693,8 +693,7 @@ Type TypeChecker::substType(Type T, TypeSubstitutionMap &Substitutions) {
if (!AnyChanged) if (!AnyChanged)
return T; return T;
return ProtocolCompositionType::get(Context, PC->getFirstLoc(), return ProtocolCompositionType::get(Context, PC->getFirstLoc(), Protocols);
Context.AllocateCopy(Protocols));
} }
} }