Skip to content

Clean up matchTypes() and related code a little #21763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6367,13 +6367,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
toType->getCanonicalType() });
if (knownRestriction != solution.ConstraintRestrictions.end()) {
switch (knownRestriction->second) {

case ConversionRestrictionKind::TupleToTuple:
case ConversionRestrictionKind::LValueToRValue:
// Restrictions that don't need to be recorded.
// Should match recordRestriction() in CSSimplify
break;

case ConversionRestrictionKind::DeepEquality: {
if (toType->hasUnresolvedType())
break;
Expand Down
7 changes: 0 additions & 7 deletions lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7293,13 +7293,6 @@ bool FailureDiagnosis::diagnoseMemberFailures(
baseObjTy = baseTy->getWithoutSpecifierType();
}

if (baseTy->is<InOutType>()) {
auto diag = diagnose(baseExpr->getLoc(), diag::extraneous_address_of);
if (auto *IOE = dyn_cast<InOutExpr>(baseExpr->getSemanticsProvidingExpr()))
diag.fixItRemove(IOE->getStartLoc());
return true;
}

// If the base type is an IUO, look through it. Odds are, the code is not
// trying to find a member of it.
// FIXME: We need to rework this with IUOs out of the type system.
Expand Down
155 changes: 53 additions & 102 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1667,9 +1667,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
auto desugar1 = type1->getDesugaredType();
auto desugar2 = type2->getDesugaredType();

auto *typeVar1 = desugar1->getAs<TypeVariableType>();
auto *typeVar2 = desugar2->getAs<TypeVariableType>();

// If the types are obviously equivalent, we're done.
if (desugar1->isEqual(desugar2))
return getTypeMatchSuccess();
Expand Down Expand Up @@ -1699,6 +1696,9 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
return getTypeMatchAmbiguous();
};

auto *typeVar1 = dyn_cast<TypeVariableType>(desugar1);
auto *typeVar2 = dyn_cast<TypeVariableType>(desugar2);

// If either (or both) types are type variables, unify the type variables.
if (typeVar1 || typeVar2) {
// Handle the easy case of both being type variables, and being
Expand Down Expand Up @@ -1800,11 +1800,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentConversion:
case ConstraintKind::OperatorArgumentConversion:
// We couldn't solve this constraint. If only one of the types is a type
// variable, perhaps we can do something with it below.
if (typeVar1 && typeVar2)
return formUnsolvedResult();
break;
return formUnsolvedResult();

case ConstraintKind::ApplicableFunction:
case ConstraintKind::DynamicCallableApplicableFunction:
Expand All @@ -1830,11 +1826,14 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}

bool isTypeVarOrMember1 = desugar1->isTypeVariableOrMember();
bool isTypeVarOrMember2 = desugar2->isTypeVariableOrMember();
// If one of the types is a member type of a type variable type,
// there's nothing we can do.
if (desugar1->isTypeVariableOrMember() ||
desugar2->isTypeVariableOrMember()) {
return formUnsolvedResult();
}

llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes;
bool concrete = !isTypeVarOrMember1 && !isTypeVarOrMember2;

// Decompose parallel structure.
TypeMatchOptions subflags =
Expand All @@ -1854,35 +1853,39 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
#define BUILTIN_TYPE(id, parent) case TypeKind::id:
#define TYPE(id, parent)
#include "swift/AST/TypeNodes.def"
case TypeKind::Module:
if (desugar1 == desugar2) {
return getTypeMatchSuccess();
}
return getTypeMatchFailure(locator);

case TypeKind::Error:
case TypeKind::Unresolved:
return getTypeMatchFailure(locator);
return getTypeMatchFailure(locator);

case TypeKind::GenericTypeParam:
llvm_unreachable("unmapped dependent type in type checker");

case TypeKind::TypeVariable:
llvm_unreachable("type variables should have already been handled by now");

case TypeKind::DependentMember:
// Nothing we can solve.
return formUnsolvedResult();

case TypeKind::TypeVariable:
case TypeKind::Module:
case TypeKind::PrimaryArchetype:
case TypeKind::OpenedArchetype:
case TypeKind::NestedArchetype:
// Nothing to do here; handle type variables and archetypes below.
break;
// If two module types or archetypes were not already equal, there's
// nothing more we can do.
return getTypeMatchFailure(locator);

case TypeKind::Tuple: {
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
// Try the tuple-to-tuple conversion.
if (!type1->is<LValueType>())
conversionsOrFixes.push_back(ConversionRestrictionKind::TupleToTuple);
auto result = matchTupleTypes(cast<TupleType>(desugar1),
cast<TupleType>(desugar2),
kind, subflags, locator);
if (result != SolutionKind::Error)
return result;

// FIXME: All cases in this switch should go down to the fix logic
// to give repairFailures() a chance to run, but this breaks stuff
// right now.
break;
}

Expand All @@ -1891,11 +1894,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
case TypeKind::Class: {
auto nominal1 = cast<NominalType>(desugar1);
auto nominal2 = cast<NominalType>(desugar2);
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
if (!type1->is<LValueType>() &&
nominal1->getDecl() == nominal2->getDecl()) {
if (nominal1->getDecl() == nominal2->getDecl())
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
}

// Check for CF <-> ObjectiveC bridging.
if (isa<ClassType>(desugar1) &&
Expand All @@ -1904,19 +1904,15 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
auto class2 = cast<ClassDecl>(nominal2->getDecl());

// CF -> Objective-C via toll-free bridging.
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
if (!type1->is<LValueType>() &&
class1->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
if (class1->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
class2->getForeignClassKind() != ClassDecl::ForeignKind::CFType &&
class1->getAttrs().hasAttribute<ObjCBridgedAttr>()) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::CFTollFreeBridgeToObjC);
}

// Objective-C -> CF via toll-free bridging.
assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
if (!type1->is<LValueType>() &&
class2->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
if (class2->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
class1->getForeignClassKind() != ClassDecl::ForeignKind::CFType &&
class2->getAttrs().hasAttribute<ObjCBridgedAttr>()) {
conversionsOrFixes.push_back(
Expand Down Expand Up @@ -2001,16 +1997,24 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
auto bound1 = cast<BoundGenericType>(desugar1);
auto bound2 = cast<BoundGenericType>(desugar2);

assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
if (!type1->is<LValueType>() && bound1->getDecl() == bound2->getDecl()) {
if (bound1->getDecl() == bound2->getDecl())
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
}
break;
}
}
}

if (concrete && kind >= ConstraintKind::Subtype) {
if (kind >= ConstraintKind::Conversion) {
// An lvalue of type T1 can be converted to a value of type T2 so long as
// T1 is convertible to T2 (by loading the value). Note that we cannot get
// a value of inout type as an lvalue though.
if (type1->is<LValueType>() && !type2->is<InOutType>()) {
return matchTypes(type1->getRValueType(), type2,
kind, subflags, locator);
}
}

if (kind >= ConstraintKind::Subtype) {
// Subclass-to-superclass conversion.
if (type1->mayHaveSuperclass() &&
type2->getClassOrBoundGenericClass() &&
Expand Down Expand Up @@ -2166,14 +2170,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
return getTypeMatchSuccess();
}

if (concrete && kind >= ConstraintKind::Conversion) {
// An lvalue of type T1 can be converted to a value of type T2 so long as
// T1 is convertible to T2 (by loading the value). Note that we cannot get
// a value of inout type as an lvalue though.
if (type1->is<LValueType>() && !type2->is<InOutType>())
conversionsOrFixes.push_back(
ConversionRestrictionKind::LValueToRValue);

if (kind >= ConstraintKind::Conversion) {
// It is never legal to form an autoclosure that results in these
// implicit conversions to pointer types.
bool isAutoClosureArgument = false;
Expand Down Expand Up @@ -2301,7 +2298,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}

if (concrete && kind >= ConstraintKind::OperatorArgumentConversion) {
if (kind >= ConstraintKind::OperatorArgumentConversion) {
// If the RHS is an inout type, the LHS must be an @lvalue type.
if (auto *lvt = type1->getAs<LValueType>()) {
if (auto *iot = type2->getAs<InOutType>()) {
Expand All @@ -2317,7 +2314,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
// to U by force-unwrapping the source value.
// A value of type T, T?, or T! can be converted to type U? or U! if
// T is convertible to U.
if (concrete && !type1->is<LValueType>() && kind >= ConstraintKind::Subtype) {
if (!type1->is<LValueType>() && kind >= ConstraintKind::Subtype) {
enumerateOptionalConversionRestrictions(
type1, type2, kind, locator,
[&](ConversionRestrictionKind restriction) {
Expand All @@ -2329,15 +2326,15 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
// literals.
if (auto elt = locator.last()) {
if (elt->getKind() == ConstraintLocator::ClosureResult) {
if (concrete && kind >= ConstraintKind::Subtype &&
if (kind >= ConstraintKind::Subtype &&
(type1->isUninhabited() || type2->isVoid())) {
increaseScore(SK_FunctionConversion);
return getTypeMatchSuccess();
}
}
}

if (concrete && kind == ConstraintKind::BindParam) {
if (kind == ConstraintKind::BindParam) {
if (auto *iot = dyn_cast<InOutType>(desugar1)) {
if (auto *lvt = dyn_cast<LValueType>(desugar2)) {
return matchTypes(iot->getObjectType(), lvt->getObjectType(),
Expand All @@ -2351,7 +2348,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
// Attempt fixes iff it's allowed, both types are concrete and
// we are not in the middle of attempting one already.
bool attemptFixes =
shouldAttemptFixes() && concrete && !flags.contains(TMF_ApplyingFix);
shouldAttemptFixes() && !flags.contains(TMF_ApplyingFix);

// When we hit this point, we're committed to the set of potential
// conversions recorded thus far.
Expand Down Expand Up @@ -2421,7 +2418,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
ForceDowncast::create(*this, type2, getConstraintLocator(locator)));
}

if (type2->getRValueType()->is<InOutType>()) {
if (type2->is<InOutType>()) {
if (type1->is<LValueType>()) {
// If we're converting an lvalue to an inout type, add the missing '&'.
conversionsOrFixes.push_back(
Expand All @@ -2446,14 +2443,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
if (attemptFixes)
repairFailures(*this, type1, type2, conversionsOrFixes, locator);

if (conversionsOrFixes.empty()) {
// If one of the types is a type variable or member thereof, we leave this
// unsolved.
if (isTypeVarOrMember1 || isTypeVarOrMember2)
return formUnsolvedResult();

if (conversionsOrFixes.empty())
return getTypeMatchFailure(locator);
}

// Where there is more than one potential conversion, create a disjunction
// so that we'll explore all of the options.
Expand Down Expand Up @@ -4930,6 +4921,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
ConstraintKind matchKind,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
assert(!type1->isTypeVariableOrMember() && !type2->isTypeVariableOrMember());

// Add to the score based on context.
auto addContextualScore = [&] {
// Okay, we need to perform one or more conversions. If this
Expand All @@ -4941,41 +4934,18 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
}
};

// Local function to form an unsolved result.
auto formUnsolved = [&] {
if (flags.contains(TMF_GenerateConstraints)) {
addUnsolvedConstraint(
Constraint::createRestricted(
*this, matchKind, restriction, type1, type2,
getConstraintLocator(locator)));

return SolutionKind::Solved;
}

return SolutionKind::Unsolved;
};

TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);

switch (restriction) {
// for $< in { <, <c, <oc }:
// T_i $< U_i ===> (T_i...) $< (U_i...)
case ConversionRestrictionKind::TupleToTuple:
return matchTupleTypes(type1->castTo<TupleType>(),
type2->castTo<TupleType>(),
matchKind, subflags, locator);

case ConversionRestrictionKind::DeepEquality:
return matchDeepEqualityTypes(type1, type2, locator);

case ConversionRestrictionKind::Superclass:
addContextualScore();
return matchSuperclassTypes(type1, type2, subflags, locator);

case ConversionRestrictionKind::LValueToRValue:
return matchTypes(type1->getRValueType(), type2,
matchKind, subflags, locator);

// for $< in { <, <c, <oc }:
// T $< U, U : P_i ===> T $< protocol<P_i...>
case ConversionRestrictionKind::Existential:
Expand Down Expand Up @@ -5027,9 +4997,6 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
increaseScore(SK_ValueToOptional);

assert(matchKind >= ConstraintKind::Subtype);
if (type2->isTypeVariableOrMember())
return formUnsolved();

if (auto generic2 = type2->getAs<BoundGenericType>()) {
if (generic2->getDecl()->isOptionalDecl()) {
return matchTypes(type1, generic2->getGenericArgs()[0],
Expand All @@ -5051,9 +5018,6 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
case ConversionRestrictionKind::OptionalToOptional: {
addContextualScore();

if (type1->isTypeVariableOrMember() || type2->isTypeVariableOrMember())
return formUnsolved();

assert(matchKind >= ConstraintKind::Subtype);
if (auto generic1 = type1->getAs<BoundGenericType>()) {
if (auto generic2 = type2->getAs<BoundGenericType>()) {
Expand Down Expand Up @@ -5296,18 +5260,6 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
llvm_unreachable("bad conversion restriction");
}

// Restrictions where CSApply can figure out the correct action from the shape of
// the types, rather than needing a record of the choice made.
static bool recordRestriction(ConversionRestrictionKind restriction) {
switch(restriction) {
case ConversionRestrictionKind::TupleToTuple:
case ConversionRestrictionKind::LValueToRValue:
return false;
default:
return true;
}
}

ConstraintSystem::SolutionKind
ConstraintSystem::simplifyRestrictedConstraint(
ConversionRestrictionKind restriction,
Expand All @@ -5318,8 +5270,7 @@ ConstraintSystem::simplifyRestrictedConstraint(
switch (simplifyRestrictedConstraintImpl(restriction, type1, type2,
matchKind, flags, locator)) {
case SolutionKind::Solved:
if (recordRestriction(restriction))
ConstraintRestrictions.push_back(std::make_tuple(type1, type2, restriction));
ConstraintRestrictions.push_back(std::make_tuple(type1, type2, restriction));
return SolutionKind::Solved;

case SolutionKind::Unsolved:
Expand Down
4 changes: 0 additions & 4 deletions lib/Sema/Constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,14 +428,10 @@ void Constraint::dump(ConstraintSystem *CS) const {

StringRef swift::constraints::getName(ConversionRestrictionKind kind) {
switch (kind) {
case ConversionRestrictionKind::TupleToTuple:
return "[tuple-to-tuple]";
case ConversionRestrictionKind::DeepEquality:
return "[deep equality]";
case ConversionRestrictionKind::Superclass:
return "[superclass]";
case ConversionRestrictionKind::LValueToRValue:
return "[lvalue-to-rvalue]";
case ConversionRestrictionKind::Existential:
return "[existential]";
case ConversionRestrictionKind::MetatypeToExistentialMetatype:
Expand Down
Loading