mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Constraint solver] Remove 'type member' constraint.
Only some fallback code in the for-each binding checking code was using this constraint. Implement those checks more directly.
This commit is contained in:
@@ -2109,25 +2109,6 @@ static bool isConversionConstraint(const Constraint *C) {
|
||||
return C->getClassification() == ConstraintClassification::Relational;
|
||||
}
|
||||
|
||||
/// Return true if this member constraint is a low priority for diagnostics, so
|
||||
/// low that we would only like to issue an error message about it if there is
|
||||
/// nothing else interesting we can scrape out of the constraint system.
|
||||
static bool isLowPriorityConstraint(Constraint *C) {
|
||||
// If the member constraint is a ".Iterator" lookup to find the iterator
|
||||
// type in a foreach loop, or a ".Element" lookup to find its element type,
|
||||
// then it is very low priority: We will get a better and more useful
|
||||
// diagnostic from the failed conversion to Sequence that will fail as well.
|
||||
if (C->getKind() == ConstraintKind::TypeMember) {
|
||||
if (auto *loc = C->getLocator())
|
||||
for (auto Elt : loc->getPath())
|
||||
if (Elt.getKind() == ConstraintLocator::GeneratorElementType ||
|
||||
Elt.getKind() == ConstraintLocator::SequenceIteratorProtocol)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Attempt to diagnose a failure without taking into account the specific
|
||||
/// kind of expression that could not be type checked.
|
||||
bool FailureDiagnosis::diagnoseConstraintFailure() {
|
||||
@@ -2148,9 +2129,6 @@ bool FailureDiagnosis::diagnoseConstraintFailure() {
|
||||
// This is a predicate that classifies constraints according to our
|
||||
// priorities.
|
||||
std::function<void (Constraint*)> classifyConstraint = [&](Constraint *C) {
|
||||
if (isLowPriorityConstraint(C))
|
||||
return rankedConstraints.push_back({C, CR_OtherConstraint});
|
||||
|
||||
if (isMemberConstraint(C))
|
||||
return rankedConstraints.push_back({C, CR_MemberConstraint});
|
||||
|
||||
|
||||
@@ -686,7 +686,6 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
|
||||
case ConstraintKind::LiteralConformsTo:
|
||||
case ConstraintKind::OptionalObject:
|
||||
case ConstraintKind::SelfObjectOfProtocol:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::ValueMember:
|
||||
llvm_unreachable("Not a call argument constraint");
|
||||
@@ -813,7 +812,6 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
||||
case ConstraintKind::LiteralConformsTo:
|
||||
case ConstraintKind::OptionalObject:
|
||||
case ConstraintKind::SelfObjectOfProtocol:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::ValueMember:
|
||||
llvm_unreachable("Not a conversion");
|
||||
@@ -940,7 +938,6 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
|
||||
case ConstraintKind::LiteralConformsTo:
|
||||
case ConstraintKind::OptionalObject:
|
||||
case ConstraintKind::SelfObjectOfProtocol:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::ValueMember:
|
||||
return false;
|
||||
@@ -1006,7 +1003,6 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
||||
case ConstraintKind::LiteralConformsTo:
|
||||
case ConstraintKind::OptionalObject:
|
||||
case ConstraintKind::SelfObjectOfProtocol:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::ValueMember:
|
||||
llvm_unreachable("Not a relational constraint");
|
||||
@@ -1431,7 +1427,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
||||
case ConstraintKind::LiteralConformsTo:
|
||||
case ConstraintKind::OptionalObject:
|
||||
case ConstraintKind::SelfObjectOfProtocol:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::ValueMember:
|
||||
llvm_unreachable("Not a relational constraint");
|
||||
@@ -2969,40 +2964,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
|
||||
return result;
|
||||
}
|
||||
|
||||
// If we want member types only, use member type lookup.
|
||||
if (constraintKind == ConstraintKind::TypeMember) {
|
||||
// Types don't have compound names.
|
||||
// FIXME: Customize diagnostic to mention types and compound names.
|
||||
if (!memberName.isSimpleName())
|
||||
return result; // No result.
|
||||
|
||||
NameLookupOptions lookupOptions = defaultMemberTypeLookupOptions;
|
||||
if (isa<AbstractFunctionDecl>(DC))
|
||||
lookupOptions |= NameLookupFlags::KnownPrivate;
|
||||
|
||||
// If we're doing a lookup for diagnostics, include inaccessible members,
|
||||
// the diagnostics machinery will sort it out.
|
||||
if (includeInaccessibleMembers)
|
||||
lookupOptions |= NameLookupFlags::IgnoreAccessibility;
|
||||
|
||||
auto lookup = TC.lookupMemberType(DC, baseObjTy, memberName.getBaseName(),
|
||||
lookupOptions);
|
||||
// Form the overload set.
|
||||
for (auto candidate : lookup) {
|
||||
// If the result is invalid, don't cascade errors.
|
||||
TC.validateDecl(candidate.first, true);
|
||||
if (candidate.first->isInvalid())
|
||||
return result.markErrorAlreadyDiagnosed();
|
||||
|
||||
result.addViable(OverloadChoice(baseTy, candidate.first,
|
||||
/*isSpecialized=*/false,
|
||||
functionRefKind));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Look for members within the base.
|
||||
LookupResult &lookup = lookupMember(baseObjTy, memberName);
|
||||
|
||||
@@ -3303,32 +3264,6 @@ ConstraintSystem::simplifyMemberConstraint(ConstraintKind kind,
|
||||
// If the lookup found no hits at all (either viable or unviable), diagnose it
|
||||
// as such and try to recover in various ways.
|
||||
|
||||
if (kind == ConstraintKind::TypeMember) {
|
||||
// If the base type was an optional, try to look through it.
|
||||
if (shouldAttemptFixes() && baseObjTy->getOptionalObjectType()) {
|
||||
// Determine whether or not we want to provide an optional chaining fixit or
|
||||
// a force unwrap fixit.
|
||||
bool optionalChain;
|
||||
if (!getContextualType())
|
||||
optionalChain = !(Options & ConstraintSystemFlags::PreferForceUnwrapToOptional);
|
||||
else
|
||||
optionalChain = !getContextualType()->getOptionalObjectType().isNull();
|
||||
auto fixKind = optionalChain ? FixKind::OptionalChaining : FixKind::ForceOptional;
|
||||
|
||||
// Note the fix.
|
||||
if (recordFix(fixKind, locator))
|
||||
return SolutionKind::Error;
|
||||
|
||||
// Look through one level of optional.
|
||||
addTypeMemberConstraint(baseObjTy->getOptionalObjectType(),
|
||||
member, memberTy, locator);
|
||||
return SolutionKind::Solved;
|
||||
}
|
||||
|
||||
return SolutionKind::Error;
|
||||
}
|
||||
|
||||
|
||||
auto instanceTy = baseObjTy;
|
||||
if (auto MTT = instanceTy->getAs<MetatypeType>())
|
||||
instanceTy = MTT->getInstanceType();
|
||||
@@ -4207,7 +4142,6 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
|
||||
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::BindOverload:
|
||||
case ConstraintKind::Disjunction:
|
||||
llvm_unreachable("Use the correct addConstraint()");
|
||||
@@ -4328,7 +4262,6 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
|
||||
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::TypeMember:
|
||||
return simplifyMemberConstraint(constraint.getKind(),
|
||||
constraint.getFirstType(),
|
||||
constraint.getMember(),
|
||||
|
||||
@@ -720,7 +720,6 @@ static bool shouldBindToValueType(Constraint *constraint)
|
||||
case ConstraintKind::DynamicTypeOf:
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::Defaultable:
|
||||
case ConstraintKind::Disjunction:
|
||||
llvm_unreachable("shouldBindToValueType() may only be called on "
|
||||
@@ -950,7 +949,6 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
|
||||
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::TypeMember:
|
||||
// If our type variable shows up in the base type, there's
|
||||
// nothing to do.
|
||||
// FIXME: Can we avoid simplification here?
|
||||
|
||||
@@ -77,7 +77,6 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
|
||||
assert(!Member && "Relational constraint cannot have a member");
|
||||
break;
|
||||
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
assert(Member && "Member constraint has no member");
|
||||
@@ -175,7 +174,6 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
|
||||
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::TypeMember:
|
||||
return create(cs, getKind(), getFirstType(), getSecondType(), getMember(),
|
||||
getFunctionRefKind(), getLocator());
|
||||
|
||||
@@ -291,9 +289,6 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
Out << "[(implicit) ." << Types.Member << ": value] == ";
|
||||
break;
|
||||
case ConstraintKind::TypeMember:
|
||||
Out << "[." << Types.Member << ": type] == ";
|
||||
break;
|
||||
case ConstraintKind::Defaultable:
|
||||
Out << " can default to ";
|
||||
break;
|
||||
@@ -462,7 +457,6 @@ gatherReferencedTypeVars(Constraint *constraint,
|
||||
case ConstraintKind::CheckedCast:
|
||||
case ConstraintKind::Equal:
|
||||
case ConstraintKind::Subtype:
|
||||
case ConstraintKind::TypeMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::DynamicTypeOf:
|
||||
|
||||
@@ -114,9 +114,6 @@ enum class ConstraintKind : char {
|
||||
/// name, and the type of that member, when referenced as a value, is the
|
||||
/// second type.
|
||||
UnresolvedValueMember,
|
||||
/// \brief The first type has a type member with the given name, and the
|
||||
/// type of that member, when referenced as a type, is the second type.
|
||||
TypeMember,
|
||||
/// \brief The first type can be defaulted to the second (which currently
|
||||
/// cannot be dependent). This is more like a type property than a
|
||||
/// relational constraint.
|
||||
@@ -485,7 +482,6 @@ public:
|
||||
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::TypeMember:
|
||||
return ConstraintClassification::Member;
|
||||
|
||||
case ConstraintKind::DynamicTypeOf:
|
||||
@@ -519,16 +515,14 @@ public:
|
||||
/// \brief Retrieve the name of the member for a member constraint.
|
||||
DeclName getMember() const {
|
||||
assert(Kind == ConstraintKind::ValueMember ||
|
||||
Kind == ConstraintKind::UnresolvedValueMember ||
|
||||
Kind == ConstraintKind::TypeMember);
|
||||
Kind == ConstraintKind::UnresolvedValueMember);
|
||||
return Types.Member;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this constraint kind has a second type.
|
||||
static bool hasMember(ConstraintKind kind) {
|
||||
return kind == ConstraintKind::ValueMember
|
||||
|| kind == ConstraintKind::UnresolvedValueMember
|
||||
|| kind == ConstraintKind::TypeMember;
|
||||
|| kind == ConstraintKind::UnresolvedValueMember;
|
||||
}
|
||||
|
||||
/// Determine the kind of function reference we have for a member reference.
|
||||
|
||||
@@ -1336,32 +1336,6 @@ public:
|
||||
resolveOverload(locator, boundTy, choice);
|
||||
}
|
||||
|
||||
/// \brief Add a value member constraint to the constraint system.
|
||||
void addTypeMemberConstraint(Type baseTy, DeclName name, Type memberTy,
|
||||
ConstraintLocatorBuilder locator) {
|
||||
assert(baseTy);
|
||||
assert(memberTy);
|
||||
assert(name);
|
||||
switch (simplifyMemberConstraint(ConstraintKind::TypeMember, baseTy, name,
|
||||
memberTy, FunctionRefKind::Compound,
|
||||
TMF_GenerateConstraints, locator)) {
|
||||
case SolutionKind::Unsolved:
|
||||
llvm_unreachable("Unsolved result when generating constraints!");
|
||||
|
||||
case SolutionKind::Solved:
|
||||
break;
|
||||
|
||||
case SolutionKind::Error:
|
||||
if (shouldAddNewFailingConstraint()) {
|
||||
addNewFailingConstraint(
|
||||
Constraint::create(*this, ConstraintKind::TypeMember, baseTy,
|
||||
memberTy, name, FunctionRefKind::Compound,
|
||||
getConstraintLocator(locator)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Add a value member constraint to the constraint system.
|
||||
void addValueMemberConstraint(Type baseTy, DeclName name, Type memberTy,
|
||||
FunctionRefKind functionRefKind,
|
||||
|
||||
@@ -2017,6 +2017,11 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
|
||||
|
||||
auto sequenceType = expr->getType()->getRValueType();
|
||||
|
||||
// Look through one level of optional; this improves recovery but doesn't
|
||||
// change the result.
|
||||
if (auto sequenceObjectType = sequenceType->getAnyOptionalObjectType())
|
||||
sequenceType = sequenceObjectType;
|
||||
|
||||
// If the sequence type is an existential, we should not attempt to
|
||||
// look up the member type at all, since we cannot represent associated
|
||||
// types of existentials.
|
||||
@@ -2053,22 +2058,11 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
|
||||
}
|
||||
}
|
||||
|
||||
// If the type lookup failed, just add some constraints we can
|
||||
// try to solve later.
|
||||
if (elementType.isNull()) {
|
||||
// Determine the iterator type of the sequence.
|
||||
iteratorType = cs.createTypeVariable(Locator, /*options=*/0);
|
||||
cs.addTypeMemberConstraint(SequenceType, tc.Context.Id_Iterator,
|
||||
iteratorType, iteratorLocator);
|
||||
|
||||
// Determine the element type of the iterator.
|
||||
// FIXME: Should look up the type witness.
|
||||
elementType = cs.createTypeVariable(Locator, /*options=*/0);
|
||||
cs.addTypeMemberConstraint(iteratorType, tc.Context.Id_Element,
|
||||
elementType, elementLocator);
|
||||
elementType = cs.createTypeVariable(elementLocator,
|
||||
TVO_MustBeMaterializable);
|
||||
}
|
||||
|
||||
|
||||
// Add a conversion constraint between the element type of the sequence
|
||||
// and the type of the element pattern.
|
||||
cs.addConstraint(ConstraintKind::Conversion, elementType, InitType,
|
||||
|
||||
Reference in New Issue
Block a user