mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #85902 from slavapestov/csbindings-cleanups
Sema: A few more simple CSBindings cleanups
This commit is contained in:
@@ -147,6 +147,8 @@ struct PotentialBinding {
|
||||
return {placeholderTy, AllowedBindingKind::Exact,
|
||||
PointerUnion<Constraint *, ConstraintLocator *>()};
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream &out, const PrintOptions &PO) const;
|
||||
};
|
||||
|
||||
struct LiteralRequirement {
|
||||
|
||||
@@ -38,15 +38,6 @@ void ConstraintGraphNode::initBindingSet() {
|
||||
Set.emplace(CG.getConstraintSystem(), TypeVar, Potential);
|
||||
}
|
||||
|
||||
/// Check whether there exists a type that could be implicitly converted
|
||||
/// to a given type i.e. is the given type is Double or Optional<..> this
|
||||
/// function is going to return true because CGFloat could be converted
|
||||
/// to a Double and non-optional value could be injected into an optional.
|
||||
static bool hasConversions(Type);
|
||||
|
||||
static std::optional<Type> checkTypeOfBinding(TypeVariableType *typeVar,
|
||||
Type type);
|
||||
|
||||
BindingSet::BindingSet(ConstraintSystem &CS, TypeVariableType *TypeVar,
|
||||
const PotentialBindings &info)
|
||||
: CS(CS), TypeVar(TypeVar), Info(info) {
|
||||
@@ -121,6 +112,73 @@ bool PotentialBinding::isViableForJoin() const {
|
||||
!isDefaultableBinding();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct PrintableBinding {
|
||||
private:
|
||||
enum class BindingKind { Exact, Subtypes, Supertypes, Literal };
|
||||
BindingKind Kind;
|
||||
Type BindingType;
|
||||
bool Viable;
|
||||
PrintableBinding(BindingKind kind, Type bindingType, bool viable)
|
||||
: Kind(kind), BindingType(bindingType), Viable(viable) {}
|
||||
|
||||
public:
|
||||
static PrintableBinding supertypesOf(Type binding) {
|
||||
return PrintableBinding{BindingKind::Supertypes, binding, true};
|
||||
}
|
||||
|
||||
static PrintableBinding subtypesOf(Type binding) {
|
||||
return PrintableBinding{BindingKind::Subtypes, binding, true};
|
||||
}
|
||||
|
||||
static PrintableBinding exact(Type binding) {
|
||||
return PrintableBinding{BindingKind::Exact, binding, true};
|
||||
}
|
||||
|
||||
static PrintableBinding literalDefaultType(Type binding, bool viable) {
|
||||
return PrintableBinding{BindingKind::Literal, binding, viable};
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream &out, const PrintOptions &PO,
|
||||
unsigned indent = 0) const {
|
||||
switch (Kind) {
|
||||
case BindingKind::Exact:
|
||||
break;
|
||||
case BindingKind::Subtypes:
|
||||
out << "(subtypes of) ";
|
||||
break;
|
||||
case BindingKind::Supertypes:
|
||||
out << "(supertypes of) ";
|
||||
break;
|
||||
case BindingKind::Literal:
|
||||
out << "(default type of literal) ";
|
||||
break;
|
||||
}
|
||||
if (BindingType)
|
||||
BindingType.print(out, PO);
|
||||
if (!Viable)
|
||||
out << " [literal not viable]";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void PotentialBinding::print(llvm::raw_ostream &out,
|
||||
const PrintOptions &PO) const {
|
||||
switch (Kind) {
|
||||
case AllowedBindingKind::Exact:
|
||||
PrintableBinding::exact(BindingType).print(out, PO);
|
||||
break;
|
||||
case AllowedBindingKind::Supertypes:
|
||||
PrintableBinding::supertypesOf(BindingType).print(out, PO);
|
||||
break;
|
||||
case AllowedBindingKind::Subtypes:
|
||||
PrintableBinding::subtypesOf(BindingType).print(out, PO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool BindingSet::isDelayed() const {
|
||||
if (auto *locator = TypeVar->getImpl().getLocator()) {
|
||||
if (locator->isLastElement<LocatorPathElt::MemberRefBase>()) {
|
||||
@@ -228,10 +286,11 @@ bool BindingSet::involvesTypeVariables() const {
|
||||
TypeVar->getImpl().canBindToPack())
|
||||
return true;
|
||||
|
||||
// This is effectively O(1) right now since bindings are re-computed
|
||||
// on each step of the solver, but once bindings are computed
|
||||
// incrementally it becomes more important to double-check that
|
||||
// any adjacent type variables found previously are still unresolved.
|
||||
// This is effectively a no-op right now since bindings are re-computed
|
||||
// on each step of the solver and fixed types won't appear in AdjancentVars,
|
||||
// but once bindings are computed incrementally it becomes important
|
||||
// to double-check that any adjacent type variables found previously are
|
||||
// still unresolved.
|
||||
return llvm::any_of(AdjacentVars, [](TypeVariableType *typeVar) {
|
||||
return !typeVar->getImpl().getFixedType(/*record=*/nullptr);
|
||||
});
|
||||
@@ -967,15 +1026,6 @@ void BindingSet::determineLiteralCoverage() {
|
||||
}
|
||||
|
||||
void BindingSet::addLiteralRequirement(Constraint *constraint) {
|
||||
auto isDirectRequirement = [&](Constraint *constraint) -> bool {
|
||||
if (auto *typeVar = constraint->getFirstType()->getAs<TypeVariableType>()) {
|
||||
auto *repr = CS.getRepresentative(typeVar);
|
||||
return repr == TypeVar;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto *protocol = constraint->getProtocol();
|
||||
|
||||
// Let's try to coalesce integer and floating point literal protocols
|
||||
@@ -1001,23 +1051,25 @@ void BindingSet::addLiteralRequirement(Constraint *constraint) {
|
||||
if (Literals.count(protocol) > 0)
|
||||
return;
|
||||
|
||||
auto isDirectRequirement = [&](Constraint *constraint) -> bool {
|
||||
if (auto *typeVar = constraint->getFirstType()->getAs<TypeVariableType>()) {
|
||||
auto *repr = CS.getRepresentative(typeVar);
|
||||
return repr == TypeVar;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
bool isDirect = isDirectRequirement(constraint);
|
||||
|
||||
// Coverage is not applicable to `ExpressibleByNilLiteral` since it
|
||||
// doesn't have a default type.
|
||||
if (protocol->isSpecificProtocol(
|
||||
Type defaultType;
|
||||
// `ExpressibleByNilLiteral` doesn't have a default type.
|
||||
if (!protocol->isSpecificProtocol(
|
||||
KnownProtocolKind::ExpressibleByNilLiteral)) {
|
||||
Literals.insert(
|
||||
{protocol, LiteralRequirement(constraint,
|
||||
/*DefaultType=*/Type(), isDirect)});
|
||||
return;
|
||||
defaultType = TypeChecker::getDefaultType(protocol, CS.DC);
|
||||
}
|
||||
|
||||
// Check whether any of the existing bindings covers this literal
|
||||
// protocol.
|
||||
LiteralRequirement literal(
|
||||
constraint, TypeChecker::getDefaultType(protocol, CS.DC), isDirect);
|
||||
|
||||
LiteralRequirement literal(constraint, defaultType, isDirect);
|
||||
Literals.insert({protocol, std::move(literal)});
|
||||
}
|
||||
|
||||
@@ -1316,9 +1368,89 @@ void PotentialBindings::addPotentialBinding(TypeVariableType *TypeVar,
|
||||
binding = binding.withType(binding.BindingType->getRValueType());
|
||||
}
|
||||
|
||||
LLVM_DEBUG(
|
||||
PrintOptions PO = PrintOptions::forDebugging();
|
||||
llvm::dbgs() << "Recording ";
|
||||
TypeVar->print(llvm::dbgs(), PO);
|
||||
llvm::dbgs() << " ";
|
||||
binding.print(llvm::dbgs(), PO);
|
||||
llvm::dbgs() << " from ";
|
||||
if (auto *constraint = dyn_cast<Constraint *>(binding.BindingSource)) {
|
||||
constraint->print(llvm::dbgs(), &TypeVar->getASTContext().SourceMgr, 0);
|
||||
} else {
|
||||
auto *locator = cast<ConstraintLocator *>(binding.BindingSource);
|
||||
locator->dump(&TypeVar->getASTContext().SourceMgr, llvm::dbgs());
|
||||
}
|
||||
llvm::dbgs() << "\n");
|
||||
|
||||
Bindings.push_back(std::move(binding));
|
||||
}
|
||||
|
||||
/// Check whether the given type can be used as a binding for the given
|
||||
/// type variable.
|
||||
///
|
||||
/// \returns true if the binding is okay.
|
||||
static bool checkTypeOfBinding(TypeVariableType *typeVar, Type type) {
|
||||
// If the type references the type variable, don't permit the binding.
|
||||
if (type->hasTypeVariable()) {
|
||||
SmallPtrSet<TypeVariableType *, 4> referencedTypeVars;
|
||||
type->getTypeVariables(referencedTypeVars);
|
||||
if (referencedTypeVars.count(typeVar))
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
auto objType = type->getWithoutSpecifierType();
|
||||
|
||||
// If the type is a type variable itself, don't permit the binding.
|
||||
if (objType->is<TypeVariableType>())
|
||||
return false;
|
||||
|
||||
// Don't bind to a dependent member type, even if it's currently
|
||||
// wrapped in any number of optionals, because binding producer
|
||||
// might unwrap and try to attempt it directly later.
|
||||
if (objType->lookThroughAllOptionalTypes()->is<DependentMemberType>())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Okay, allow the binding.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check whether there exists a type that could be implicitly converted
|
||||
/// to a given type i.e. is the given type is Double or Optional<..> this
|
||||
/// function is going to return true because CGFloat could be converted
|
||||
/// to a Double and non-optional value could be injected into an optional.
|
||||
static bool hasConversions(Type type) {
|
||||
if (type->isAnyHashable() || type->isDouble() || type->isCGFloat())
|
||||
return true;
|
||||
|
||||
if (type->getAnyPointerElementType())
|
||||
return true;
|
||||
|
||||
if (auto *structTy = type->getAs<BoundGenericStructType>()) {
|
||||
if (auto eltTy = structTy->getArrayElementType()) {
|
||||
return hasConversions(eltTy);
|
||||
} else if (auto pair = ConstraintSystem::isDictionaryType(structTy)) {
|
||||
return hasConversions(pair->second);
|
||||
} else if (auto eltTy = ConstraintSystem::isSetType(structTy)) {
|
||||
return hasConversions(*eltTy);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto *enumTy = type->getAs<BoundGenericEnumType>()) {
|
||||
if (enumTy->getOptionalObjectType())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(type->is<StructType>() || type->is<EnumType>() ||
|
||||
type->is<BuiltinType>() || type->is<ArchetypeType>());
|
||||
}
|
||||
|
||||
bool BindingSet::isViable(PotentialBinding &binding, bool isTransitive) {
|
||||
// Prevent against checking against the same opened nominal type
|
||||
// over and over again. Doing so means redundant work in the best
|
||||
@@ -1395,36 +1527,6 @@ bool BindingSet::isViable(PotentialBinding &binding, bool isTransitive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hasConversions(Type type) {
|
||||
if (type->isAnyHashable() || type->isDouble() || type->isCGFloat())
|
||||
return true;
|
||||
|
||||
if (type->getAnyPointerElementType())
|
||||
return true;
|
||||
|
||||
if (auto *structTy = type->getAs<BoundGenericStructType>()) {
|
||||
if (auto eltTy = structTy->getArrayElementType()) {
|
||||
return hasConversions(eltTy);
|
||||
} else if (auto pair = ConstraintSystem::isDictionaryType(structTy)) {
|
||||
return hasConversions(pair->second);
|
||||
} else if (auto eltTy = ConstraintSystem::isSetType(structTy)) {
|
||||
return hasConversions(*eltTy);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto *enumTy = type->getAs<BoundGenericEnumType>()) {
|
||||
if (enumTy->getOptionalObjectType())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(type->is<StructType>() || type->is<EnumType>() ||
|
||||
type->is<BuiltinType>() || type->is<ArchetypeType>());
|
||||
}
|
||||
|
||||
bool BindingSet::favoredOverDisjunction(Constraint *disjunction) const {
|
||||
if (isHole())
|
||||
return false;
|
||||
@@ -1576,38 +1678,6 @@ BindingSet ConstraintSystem::getBindingsFor(TypeVariableType *typeVar) {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/// Check whether the given type can be used as a binding for the given
|
||||
/// type variable.
|
||||
///
|
||||
/// \returns the type to bind to, if the binding is okay.
|
||||
static std::optional<Type> checkTypeOfBinding(TypeVariableType *typeVar,
|
||||
Type type) {
|
||||
// If the type references the type variable, don't permit the binding.
|
||||
if (type->hasTypeVariable()) {
|
||||
SmallPtrSet<TypeVariableType *, 4> referencedTypeVars;
|
||||
type->getTypeVariables(referencedTypeVars);
|
||||
if (referencedTypeVars.count(typeVar))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
{
|
||||
auto objType = type->getWithoutSpecifierType();
|
||||
|
||||
// If the type is a type variable itself, don't permit the binding.
|
||||
if (objType->is<TypeVariableType>())
|
||||
return std::nullopt;
|
||||
|
||||
// Don't bind to a dependent member type, even if it's currently
|
||||
// wrapped in any number of optionals, because binding producer
|
||||
// might unwrap and try to attempt it directly later.
|
||||
if (objType->lookThroughAllOptionalTypes()->is<DependentMemberType>())
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Okay, allow the binding (with the simplified type).
|
||||
return type;
|
||||
}
|
||||
|
||||
std::optional<PotentialBinding>
|
||||
PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
TypeVariableType *TypeVar,
|
||||
@@ -1616,11 +1686,29 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
ConstraintClassification::Relational &&
|
||||
"only relational constraints handled here");
|
||||
|
||||
LLVM_DEBUG(
|
||||
llvm::dbgs() << "inferFromRelational(";
|
||||
TypeVar->print(llvm::dbgs(), PrintOptions::forDebugging());
|
||||
llvm::dbgs() << ", ";
|
||||
constraint->print(llvm::dbgs(), &CS.getASTContext().SourceMgr, 0);
|
||||
llvm::dbgs() << ")\n");
|
||||
|
||||
auto first = CS.simplifyType(constraint->getFirstType());
|
||||
auto second = CS.simplifyType(constraint->getSecondType());
|
||||
|
||||
if (first->is<TypeVariableType>() && first->isEqual(second))
|
||||
#define DEBUG_BAILOUT(msg) \
|
||||
LLVM_DEBUG( \
|
||||
PrintOptions PO = PrintOptions::forDebugging(); \
|
||||
llvm::dbgs() << msg << " "; \
|
||||
TypeVar->print(llvm::dbgs(), PO); \
|
||||
llvm::dbgs() << " from "; \
|
||||
constraint->print(llvm::dbgs(), &CS.getASTContext().SourceMgr); \
|
||||
llvm::dbgs() << "\n");
|
||||
|
||||
if (first->is<TypeVariableType>() && first->isEqual(second)) {
|
||||
DEBUG_BAILOUT("First is second");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Type type;
|
||||
AllowedBindingKind kind;
|
||||
@@ -1641,6 +1729,7 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
// of bindings for them until closure's body is opened.
|
||||
if (auto *typeVar = first->getAs<TypeVariableType>()) {
|
||||
if (typeVar->getImpl().isClosureType()) {
|
||||
DEBUG_BAILOUT("Delayed (1)");
|
||||
DelayedBy.push_back(constraint);
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -1674,8 +1763,10 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
}
|
||||
|
||||
// Do not attempt to bind to ErrorType.
|
||||
if (type->hasError())
|
||||
if (type->hasError()) {
|
||||
DEBUG_BAILOUT("Has error");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (TypeVar->getImpl().isKeyPathType()) {
|
||||
auto objectTy = type->lookThroughAllOptionalTypes();
|
||||
@@ -1694,8 +1785,10 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(objectTy->isKnownKeyPathType() || objectTy->is<AnyFunctionType>()))
|
||||
if (!(objectTy->isKnownKeyPathType() || objectTy->is<AnyFunctionType>())) {
|
||||
DEBUG_BAILOUT("Bad key path type (1)");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (TypeVar->getImpl().isKeyPathSubscriptIndex()) {
|
||||
@@ -1713,6 +1806,7 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
if (auto superclass = layout.explicitSuperclass) {
|
||||
type = superclass;
|
||||
} else if (!CS.shouldAttemptFixes()) {
|
||||
DEBUG_BAILOUT("Bad key path type (2)");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
@@ -1736,8 +1830,10 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
// type of a chain, Result should always be a concrete type which conforms
|
||||
// to the protocol inferred for the base.
|
||||
if (constraint->getKind() == ConstraintKind::UnresolvedMemberChainBase &&
|
||||
kind == AllowedBindingKind::Subtypes && type->is<ProtocolType>())
|
||||
kind == AllowedBindingKind::Subtypes && type->is<ProtocolType>()) {
|
||||
DEBUG_BAILOUT("Unresolved member chain base");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (constraint->getKind() == ConstraintKind::LValueObject) {
|
||||
@@ -1745,14 +1841,17 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
// not the other way around, that would be handled by constraint
|
||||
// simplification.
|
||||
if (kind == AllowedBindingKind::Subtypes) {
|
||||
if (type->isTypeVariableOrMember())
|
||||
if (type->isTypeVariableOrMember()) {
|
||||
DEBUG_BAILOUT("Disallowed l-value inference");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
type = LValueType::get(type);
|
||||
} else {
|
||||
// Right-hand side of the l-value object constraint can only
|
||||
// be bound via constraint simplification when l-value type
|
||||
// is inferred or contextually from other constraints.
|
||||
DEBUG_BAILOUT("Delayed (2)");
|
||||
DelayedBy.push_back(constraint);
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -1793,6 +1892,7 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
if (!containsSelf)
|
||||
DelayedBy.push_back(constraint);
|
||||
|
||||
DEBUG_BAILOUT("Dependent member");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -1814,13 +1914,13 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
}
|
||||
|
||||
// Check whether we can perform this binding.
|
||||
if (auto boundType = checkTypeOfBinding(TypeVar, type)) {
|
||||
type = *boundType;
|
||||
} else {
|
||||
if (!checkTypeOfBinding(TypeVar, type)) {
|
||||
auto *bindingTypeVar = type->getRValueType()->getAs<TypeVariableType>();
|
||||
|
||||
if (!bindingTypeVar)
|
||||
if (!bindingTypeVar) {
|
||||
DEBUG_BAILOUT("Not a type variable");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// If current type variable is associated with a code completion token
|
||||
// it's possible that it doesn't have enough contextual information
|
||||
@@ -1887,8 +1987,10 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
// lvalue-binding rules.
|
||||
if (auto otherTypeVar = type->getAs<TypeVariableType>()) {
|
||||
if (TypeVar->getImpl().canBindToLValue() !=
|
||||
otherTypeVar->getImpl().canBindToLValue())
|
||||
otherTypeVar->getImpl().canBindToLValue()) {
|
||||
DEBUG_BAILOUT("LValue mismatch");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (type->is<InOutType>() && !TypeVar->getImpl().canBindToInOut())
|
||||
@@ -1913,6 +2015,8 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
|
||||
return PotentialBinding{type, kind, constraint};
|
||||
}
|
||||
|
||||
#undef DEBUG_BAILOUT
|
||||
|
||||
/// Retrieve the set of potential type bindings for the given
|
||||
/// representative type variable, along with flags indicating whether
|
||||
/// those types should be opened.
|
||||
@@ -2362,54 +2466,6 @@ void BindingSet::dump(llvm::raw_ostream &out, unsigned indent) const {
|
||||
if (numDefaultable > 0)
|
||||
out << "[defaultable bindings: " << numDefaultable << "] ";
|
||||
|
||||
struct PrintableBinding {
|
||||
private:
|
||||
enum class BindingKind { Exact, Subtypes, Supertypes, Literal };
|
||||
BindingKind Kind;
|
||||
Type BindingType;
|
||||
bool Viable;
|
||||
PrintableBinding(BindingKind kind, Type bindingType, bool viable)
|
||||
: Kind(kind), BindingType(bindingType), Viable(viable) {}
|
||||
|
||||
public:
|
||||
static PrintableBinding supertypesOf(Type binding) {
|
||||
return PrintableBinding{BindingKind::Supertypes, binding, true};
|
||||
}
|
||||
|
||||
static PrintableBinding subtypesOf(Type binding) {
|
||||
return PrintableBinding{BindingKind::Subtypes, binding, true};
|
||||
}
|
||||
|
||||
static PrintableBinding exact(Type binding) {
|
||||
return PrintableBinding{BindingKind::Exact, binding, true};
|
||||
}
|
||||
|
||||
static PrintableBinding literalDefaultType(Type binding, bool viable) {
|
||||
return PrintableBinding{BindingKind::Literal, binding, viable};
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream &out, const PrintOptions &PO,
|
||||
unsigned indent = 0) const {
|
||||
switch (Kind) {
|
||||
case BindingKind::Exact:
|
||||
break;
|
||||
case BindingKind::Subtypes:
|
||||
out << "(subtypes of) ";
|
||||
break;
|
||||
case BindingKind::Supertypes:
|
||||
out << "(supertypes of) ";
|
||||
break;
|
||||
case BindingKind::Literal:
|
||||
out << "(default type of literal) ";
|
||||
break;
|
||||
}
|
||||
if (BindingType)
|
||||
BindingType.print(out, PO);
|
||||
if (!Viable)
|
||||
out << " [literal not viable]";
|
||||
}
|
||||
};
|
||||
|
||||
out << "[potential bindings: ";
|
||||
SmallVector<PrintableBinding, 2> potentialBindings;
|
||||
for (const auto &binding : Bindings) {
|
||||
@@ -2677,8 +2733,7 @@ bool TypeVarBindingProducer::computeNext() {
|
||||
|
||||
for (auto supertype : enumerateDirectSupertypes(type)) {
|
||||
// If we're not allowed to try this binding, skip it.
|
||||
if (auto simplifiedSuper = checkTypeOfBinding(TypeVar, supertype)) {
|
||||
auto supertype = *simplifiedSuper;
|
||||
if (checkTypeOfBinding(TypeVar, supertype)) {
|
||||
// A key path type cannot be bound to type-erased key path variants.
|
||||
if (TypeVar->getImpl().isKeyPathType() &&
|
||||
isTypeErasedKeyPathType(supertype))
|
||||
|
||||
@@ -910,6 +910,9 @@ bool ConstraintGraph::contractEdges() {
|
||||
if (!(tyvar1 && tyvar2))
|
||||
continue;
|
||||
|
||||
auto rep1 = CS.getRepresentative(tyvar1);
|
||||
auto rep2 = CS.getRepresentative(tyvar2);
|
||||
|
||||
// If the argument is allowed to bind to `inout`, in general,
|
||||
// it's invalid to contract the edge between argument and parameter,
|
||||
// but if we can prove that there are no possible bindings
|
||||
@@ -919,9 +922,9 @@ bool ConstraintGraph::contractEdges() {
|
||||
// Such action is valid because argument type variable can
|
||||
// only get its bindings from related overload, which gives
|
||||
// us enough information to decided on l-valueness.
|
||||
if (tyvar1->getImpl().canBindToInOut()) {
|
||||
if (rep1->getImpl().canBindToInOut()) {
|
||||
bool isNotContractable = true;
|
||||
auto bindings = CS.getBindingsFor(tyvar1);
|
||||
auto bindings = CS.getBindingsFor(rep1);
|
||||
if (bindings.isViable()) {
|
||||
// Holes can't be contracted.
|
||||
if (bindings.isHole())
|
||||
@@ -949,9 +952,6 @@ bool ConstraintGraph::contractEdges() {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto rep1 = CS.getRepresentative(tyvar1);
|
||||
auto rep2 = CS.getRepresentative(tyvar2);
|
||||
|
||||
if (CS.isDebugMode()) {
|
||||
auto indent = CS.solverState ? CS.solverState->getCurrentIndent() : 0;
|
||||
auto &log = llvm::errs().indent(indent);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// {"kind":"typecheck","original":"5af4a4fb","signature":"swift::constraints::ConstraintSystem::getBindingsFor(swift::TypeVariableType*)","signatureAssert":"Assertion failed: (typeVar->getImpl().getRepresentative(nullptr) == typeVar && \"not a representative\"), function getBindingsFor"}
|
||||
// RUN: not --crash %target-swift-frontend -typecheck %s
|
||||
// RUN: not %target-swift-frontend -typecheck %s
|
||||
struct a {
|
||||
func b(arr: [a]) {
|
||||
arr.compactMap {
|
||||
Reference in New Issue
Block a user