[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:
Doug Gregor
2016-11-06 22:52:03 -08:00
parent ed0955aa8e
commit e20464a02c
7 changed files with 10 additions and 145 deletions

View File

@@ -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});

View File

@@ -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(),

View File

@@ -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?

View File

@@ -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:

View File

@@ -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.

View File

@@ -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,

View File

@@ -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,