mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -1373,14 +1373,17 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
|
|||||||
|
|
||||||
// Check whether the type variable must be bound to a materializable
|
// Check whether the type variable must be bound to a materializable
|
||||||
// type.
|
// type.
|
||||||
if (typeVar1->getImpl().mustBeMaterializable() &&
|
if (typeVar1->getImpl().mustBeMaterializable()) {
|
||||||
!type2->isMaterializable()) {
|
if (!type2->isMaterializable()) {
|
||||||
if (shouldRecordFailures()) {
|
if (shouldRecordFailures()) {
|
||||||
// TODO: customize error message for closure vs. generic param
|
// TODO: customize error message for closure vs. generic param
|
||||||
recordFailure(getConstraintLocator(locator),
|
recordFailure(getConstraintLocator(locator),
|
||||||
Failure::IsNotMaterializable, type2);
|
Failure::IsNotMaterializable, type2);
|
||||||
|
}
|
||||||
|
return SolutionKind::Error;
|
||||||
|
} else {
|
||||||
|
setMustBeMaterializableRecursive(type2);
|
||||||
}
|
}
|
||||||
return SolutionKind::Error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A constraint that binds any pointer to a void pointer is
|
// A constraint that binds any pointer to a void pointer is
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "ConstraintSystem.h"
|
#include "ConstraintSystem.h"
|
||||||
#include "ConstraintGraph.h"
|
#include "ConstraintGraph.h"
|
||||||
#include "swift/AST/ArchetypeBuilder.h"
|
#include "swift/AST/ArchetypeBuilder.h"
|
||||||
|
#include "swift/AST/TypeWalker.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
|
||||||
using namespace swift;
|
using namespace swift;
|
||||||
@@ -127,6 +128,36 @@ void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
|
|||||||
addTypeVariableConstraintsToWorkList(typeVar);
|
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(
|
void ConstraintSystem::addTypeVariableConstraintsToWorkList(
|
||||||
TypeVariableType *typeVar) {
|
TypeVariableType *typeVar) {
|
||||||
// Gather the constraints affected by a change to this type variable.
|
// Gather the constraints affected by a change to this type variable.
|
||||||
|
|||||||
@@ -66,10 +66,13 @@ namespace constraints {
|
|||||||
class SavedTypeVariableBinding {
|
class SavedTypeVariableBinding {
|
||||||
/// \brief The type variable.
|
/// \brief The type variable.
|
||||||
TypeVariableType *TypeVar;
|
TypeVariableType *TypeVar;
|
||||||
|
|
||||||
/// \brief The parent or fixed type.
|
/// \brief The parent or fixed type.
|
||||||
llvm::PointerUnion<TypeVariableType *, TypeBase *> ParentOrFixed;
|
llvm::PointerUnion<TypeVariableType *, TypeBase *> ParentOrFixed;
|
||||||
|
|
||||||
|
/// \brief The type variable options.
|
||||||
|
unsigned Options : 3;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SavedTypeVariableBinding(TypeVariableType *typeVar);
|
explicit SavedTypeVariableBinding(TypeVariableType *typeVar);
|
||||||
|
|
||||||
@@ -287,19 +290,20 @@ public:
|
|||||||
constraints::SavedTypeVariableBindings *record) {
|
constraints::SavedTypeVariableBindings *record) {
|
||||||
// Merge the equivalence classes corresponding to these two type
|
// Merge the equivalence classes corresponding to these two type
|
||||||
// variables. Always merge 'up' the constraint stack, because it is simpler.
|
// variables. Always merge 'up' the constraint stack, because it is simpler.
|
||||||
if (getID() < other->getImpl().getID()) {
|
if (getID() > other->getImpl().getID()) {
|
||||||
auto rep = other->getImpl().getRepresentative(record);
|
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)
|
if (record)
|
||||||
rep->getImpl().recordBinding(*record);
|
recordBinding(*record);
|
||||||
rep->getImpl().ParentOrFixed = getTypeVariable();
|
Options |= TVO_MustBeMaterializable;
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,6 +339,15 @@ public:
|
|||||||
rep->getImpl().ParentOrFixed = type.getPointer();
|
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.
|
/// \brief Print the type variable to the given output stream.
|
||||||
void print(llvm::raw_ostream &OS);
|
void print(llvm::raw_ostream &OS);
|
||||||
};
|
};
|
||||||
@@ -1908,6 +1921,11 @@ public:
|
|||||||
/// a complete solution from partial solutions.
|
/// a complete solution from partial solutions.
|
||||||
void assignFixedType(TypeVariableType *typeVar, Type type,
|
void assignFixedType(TypeVariableType *typeVar, Type type,
|
||||||
bool updateState = true);
|
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>.
|
/// \brief Determine if the type in question is an Array<T>.
|
||||||
bool isArrayType(Type t);
|
bool isArrayType(Type t);
|
||||||
|
|||||||
@@ -79,9 +79,11 @@ TypeBase *TypeVariableType::getBaseBeingSubstituted() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SavedTypeVariableBinding::SavedTypeVariableBinding(TypeVariableType *typeVar)
|
SavedTypeVariableBinding::SavedTypeVariableBinding(TypeVariableType *typeVar)
|
||||||
: TypeVar(typeVar), ParentOrFixed(typeVar->getImpl().ParentOrFixed) { }
|
: TypeVar(typeVar), ParentOrFixed(typeVar->getImpl().ParentOrFixed),
|
||||||
|
Options(typeVar->getImpl().Options) { }
|
||||||
|
|
||||||
void SavedTypeVariableBinding::restore() {
|
void SavedTypeVariableBinding::restore() {
|
||||||
|
TypeVar->getImpl().Options = Options;
|
||||||
TypeVar->getImpl().ParentOrFixed = ParentOrFixed;
|
TypeVar->getImpl().ParentOrFixed = ParentOrFixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2170,6 +2172,8 @@ void ConstraintSystem::print(raw_ostream &out) {
|
|||||||
tv->getImpl().print(out);
|
tv->getImpl().print(out);
|
||||||
if (tv->getImpl().canBindToLValue())
|
if (tv->getImpl().canBindToLValue())
|
||||||
out << " [lvalue allowed]";
|
out << " [lvalue allowed]";
|
||||||
|
if (tv->getImpl().mustBeMaterializable())
|
||||||
|
out << " [must be materializable]";
|
||||||
auto rep = getRepresentative(tv);
|
auto rep = getRepresentative(tv);
|
||||||
if (rep == tv) {
|
if (rep == tv) {
|
||||||
if (auto fixed = getFixedType(tv)) {
|
if (auto fixed = getFixedType(tv)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user