When unifying two type variables, make sure the new representative type

variable has the must-be-materializable bit set if the old one does.
When assigning a fixed type to a type variable that must be
materializable, transfer the bit to any type variables within the fixed
type, as appropriate.

Add Options field to SavedTypeVariableBinding to save/restore type
variable options during solution.

<rdar://problem/21026806> Propagate MustBeMaterializable bit among type variables appropriately

Swift SVN r28883
This commit is contained in:
Chris Willmore
2015-05-21 19:53:48 +00:00
parent e0ac419249
commit df9136e0e0
4 changed files with 77 additions and 21 deletions

View File

@@ -1373,14 +1373,17 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
// Check whether the type variable must be bound to a materializable
// type.
if (typeVar1->getImpl().mustBeMaterializable() &&
!type2->isMaterializable()) {
if (shouldRecordFailures()) {
// TODO: customize error message for closure vs. generic param
recordFailure(getConstraintLocator(locator),
Failure::IsNotMaterializable, type2);
if (typeVar1->getImpl().mustBeMaterializable()) {
if (!type2->isMaterializable()) {
if (shouldRecordFailures()) {
// TODO: customize error message for closure vs. generic param
recordFailure(getConstraintLocator(locator),
Failure::IsNotMaterializable, type2);
}
return SolutionKind::Error;
} else {
setMustBeMaterializableRecursive(type2);
}
return SolutionKind::Error;
}
// A constraint that binds any pointer to a void pointer is

View File

@@ -18,6 +18,7 @@
#include "ConstraintSystem.h"
#include "ConstraintGraph.h"
#include "swift/AST/ArchetypeBuilder.h"
#include "swift/AST/TypeWalker.h"
#include "llvm/ADT/SmallString.h"
using namespace swift;
@@ -127,6 +128,36 @@ void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
addTypeVariableConstraintsToWorkList(typeVar);
}
void ConstraintSystem::setMustBeMaterializableRecursive(Type type)
{
assert(type->isMaterializable() &&
"argument to setMustBeMateriziable may not be inherently "
"non-materializable");
class Walker : public TypeWalker {
ConstraintSystem &CS;
public:
Walker(ConstraintSystem &CS) : CS(CS) {}
virtual Action walkToTypePre(Type ty) override {
if (auto varTy = dyn_cast<TypeVariableType>(ty.getPointer())) {
varTy->getImpl().setMustBeMaterializable(CS.getSavedBindings());
return Action::Continue;
} else if (isa<FunctionType>(ty.getPointer()) ||
isa<PolymorphicFunctionType>(ty.getPointer()) ||
isa<DynamicSelfType>(ty.getPointer())) {
return Action::SkipChildren;
} else if (isa<LValueType>(ty.getPointer()) ||
isa<InOutType>(ty.getPointer())) {
llvm_unreachable("attempt to setMustBeMaterializableRecursive on "
"non-materializable type");
} else {
return Action::Continue;
}
}
};
simplifyType(type).walk(Walker(*this));
}
void ConstraintSystem::addTypeVariableConstraintsToWorkList(
TypeVariableType *typeVar) {
// Gather the constraints affected by a change to this type variable.

View File

@@ -70,6 +70,9 @@ class SavedTypeVariableBinding {
/// \brief The parent or fixed type.
llvm::PointerUnion<TypeVariableType *, TypeBase *> ParentOrFixed;
/// \brief The type variable options.
unsigned Options : 3;
public:
explicit SavedTypeVariableBinding(TypeVariableType *typeVar);
@@ -287,19 +290,20 @@ public:
constraints::SavedTypeVariableBindings *record) {
// Merge the equivalence classes corresponding to these two type
// variables. Always merge 'up' the constraint stack, because it is simpler.
if (getID() < other->getImpl().getID()) {
auto rep = other->getImpl().getRepresentative(record);
if (getID() > other->getImpl().getID()) {
other->getImpl().mergeEquivalenceClasses(getTypeVariable(), record);
return;
}
auto otherRep = other->getImpl().getRepresentative(record);
if (record)
otherRep->getImpl().recordBinding(*record);
otherRep->getImpl().ParentOrFixed = getTypeVariable();
assert(otherRep->getImpl().canBindToLValue() == canBindToLValue());
if (!mustBeMaterializable() && otherRep->getImpl().mustBeMaterializable()) {
if (record)
rep->getImpl().recordBinding(*record);
rep->getImpl().ParentOrFixed = getTypeVariable();
assert(rep->getImpl().canBindToLValue() == canBindToLValue());
} else {
auto rep = getRepresentative(record);
if (record)
rep->getImpl().recordBinding(*record);
rep->getImpl().ParentOrFixed = other;
assert(rep->getImpl().canBindToLValue()
== other->getImpl().canBindToLValue());
recordBinding(*record);
Options |= TVO_MustBeMaterializable;
}
}
@@ -335,6 +339,15 @@ public:
rep->getImpl().ParentOrFixed = type.getPointer();
}
void setMustBeMaterializable(constraints::SavedTypeVariableBindings *record) {
auto rep = getRepresentative(record);
if (!rep->getImpl().mustBeMaterializable()) {
if (record)
rep->getImpl().recordBinding(*record);
rep->getImpl().Options |= TVO_MustBeMaterializable;
}
}
/// \brief Print the type variable to the given output stream.
void print(llvm::raw_ostream &OS);
};
@@ -1909,6 +1922,11 @@ public:
void assignFixedType(TypeVariableType *typeVar, Type type,
bool updateState = true);
// \brief Set the TVO_MustBeMaterializable bit on all type variables
// necessary to ensure that the type in question is materializable in a
// viable solution.
void setMustBeMaterializableRecursive(Type type);
/// \brief Determine if the type in question is an Array<T>.
bool isArrayType(Type t);

View File

@@ -79,9 +79,11 @@ TypeBase *TypeVariableType::getBaseBeingSubstituted() {
}
SavedTypeVariableBinding::SavedTypeVariableBinding(TypeVariableType *typeVar)
: TypeVar(typeVar), ParentOrFixed(typeVar->getImpl().ParentOrFixed) { }
: TypeVar(typeVar), ParentOrFixed(typeVar->getImpl().ParentOrFixed),
Options(typeVar->getImpl().Options) { }
void SavedTypeVariableBinding::restore() {
TypeVar->getImpl().Options = Options;
TypeVar->getImpl().ParentOrFixed = ParentOrFixed;
}
@@ -2170,6 +2172,8 @@ void ConstraintSystem::print(raw_ostream &out) {
tv->getImpl().print(out);
if (tv->getImpl().canBindToLValue())
out << " [lvalue allowed]";
if (tv->getImpl().mustBeMaterializable())
out << " [must be materializable]";
auto rep = getRepresentative(tv);
if (rep == tv) {
if (auto fixed = getFixedType(tv)) {