Skip to content

Commit 01fa24c

Browse files
committed
Speculatively revert "[Type checker] Eliminate the 'literalConformanceProto' state on type variables."
This reverts commit 6bdd9cf. This commit *appears* to be breaking something in Dollar involving inference with array literals and 'nil'; pull it back for more investigation.
1 parent 7ba11dd commit 01fa24c

File tree

7 files changed

+74
-101
lines changed

7 files changed

+74
-101
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2920,8 +2920,7 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
29202920
// If simplification has turned this into the same types, then this isn't the
29212921
// broken constraint that we're looking for.
29222922
if (fromType->isEqual(toType) &&
2923-
constraint->getKind() != ConstraintKind::ConformsTo &&
2924-
constraint->getKind() != ConstraintKind::LiteralConformsTo)
2923+
constraint->getKind() != ConstraintKind::ConformsTo)
29252924
return false;
29262925

29272926

lib/Sema/CSGen.cpp

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -500,47 +500,49 @@ namespace {
500500
return false;
501501
}
502502

503-
/// Determine whether the given parameter type and argument should be
503+
/// Determine whether the given parameter and argument type should be
504504
/// "favored" because they match exactly.
505505
bool isFavoredParamAndArg(ConstraintSystem &CS,
506506
Type paramTy,
507-
Expr *arg,
508507
Type argTy,
509-
Expr *otherArg = nullptr,
510-
Type otherArgTy = Type()) {
511-
// Determine the argument type.
512-
argTy = argTy->getLValueOrInOutObjectType();
513-
508+
Type otherArgTy) {
509+
if (argTy->getAs<LValueType>())
510+
argTy = argTy->getLValueOrInOutObjectType();
511+
512+
if (!otherArgTy.isNull() &&
513+
otherArgTy->getAs<LValueType>())
514+
otherArgTy = otherArgTy->getLValueOrInOutObjectType();
515+
514516
// Do the types match exactly?
515517
if (paramTy->isEqual(argTy))
516518
return true;
517-
518-
// If the argument is a literal, this is a favored param/arg pair if
519-
// the parameter is of that default type.
520-
auto &tc = CS.getTypeChecker();
521-
auto literalProto = tc.getLiteralProtocol(arg->getSemanticsProvidingExpr());
522-
if (!literalProto) return false;
523-
524-
// Dig out the second argument type.
525-
if (otherArgTy)
526-
otherArgTy = otherArgTy->getLValueOrInOutObjectType();
527-
528-
// If there is another, concrete argument, check whether it's type
529-
// conforms to the literal protocol and test against it directly.
530-
// This helps to avoid 'widening' the favored type to the default type for
531-
// the literal.
532-
if (otherArgTy && otherArgTy->getAnyNominal()) {
533-
return otherArgTy->isEqual(paramTy) &&
534-
tc.conformsToProtocol(otherArgTy, literalProto, CS.DC,
535-
ConformanceCheckFlags::InExpression);
519+
520+
// If the argument is a type variable created for a literal that has a
521+
// default type, this is a favored param/arg pair if the parameter is of
522+
// that default type.
523+
// Is the argument a type variable...
524+
if (auto argTypeVar = argTy->getAs<TypeVariableType>()) {
525+
if (auto proto = argTypeVar->getImpl().literalConformanceProto) {
526+
// If it's a struct type associated with the literal conformance,
527+
// test against it directly. This helps to avoid 'widening' the
528+
// favored type to the default type for the literal.
529+
if (!otherArgTy.isNull() &&
530+
otherArgTy->getAs<StructType>()) {
531+
532+
if (CS.TC.conformsToProtocol(otherArgTy,
533+
proto,
534+
CS.DC,
535+
ConformanceCheckFlags::InExpression)) {
536+
return otherArgTy->isEqual(paramTy);
537+
}
538+
} else if (auto defaultTy = CS.TC.getDefaultType(proto, CS.DC)) {
539+
if (paramTy->isEqual(defaultTy)) {
540+
return true;
541+
}
542+
}
543+
}
536544
}
537-
538-
// If there is a default type for the literal protocol, check whether
539-
// it is the same as the parameter type.
540-
// Check whether there is a default type to compare against.
541-
if (Type defaultType = tc.getDefaultType(literalProto, CS.DC))
542-
return paramTy->isEqual(defaultType);
543-
545+
544546
return false;
545547
}
546548

@@ -740,6 +742,9 @@ namespace {
740742
/// for the operand and contextual type.
741743
void favorMatchingUnaryOperators(ApplyExpr *expr,
742744
ConstraintSystem &CS) {
745+
// Find the argument type.
746+
auto argTy = getInnerParenType(expr->getArg()->getType());
747+
743748
// Determine whether the given declaration is favored.
744749
auto isFavoredDecl = [&](ValueDecl *value) -> bool {
745750
auto valueTy = value->getType();
@@ -757,8 +762,7 @@ namespace {
757762
auto resultTy = fnTy->getResult();
758763
auto contextualTy = CS.getContextualType(expr);
759764

760-
return isFavoredParamAndArg(CS, paramTy, expr->getArg(),
761-
expr->getArg()->getType()) &&
765+
return isFavoredParamAndArg(CS, paramTy, argTy, Type()) &&
762766
(!contextualTy || contextualTy->isEqual(resultTy));
763767
};
764768

@@ -877,10 +881,8 @@ namespace {
877881
if (!fnTy)
878882
return false;
879883

880-
Expr *firstArg = argTupleExpr->getElement(0);
881-
auto firstFavoredTy = CS.getFavoredType(firstArg);
882-
Expr *secondArg = argTupleExpr->getElement(1);
883-
auto secondFavoredTy = CS.getFavoredType(secondArg);
884+
auto firstFavoredTy = CS.getFavoredType(argTupleExpr->getElement(0));
885+
auto secondFavoredTy = CS.getFavoredType(argTupleExpr->getElement(1));
884886

885887
auto favoredExprTy = CS.getFavoredType(expr);
886888

@@ -924,10 +926,8 @@ namespace {
924926
auto contextualTy = CS.getContextualType(expr);
925927

926928
return
927-
(isFavoredParamAndArg(CS, firstParamTy, firstArg, firstArgTy,
928-
secondArg, secondArgTy) ||
929-
isFavoredParamAndArg(CS, secondParamTy, secondArg, secondArgTy,
930-
firstArg, firstArgTy)) &&
929+
(isFavoredParamAndArg(CS, firstParamTy, firstArgTy, secondArgTy) ||
930+
isFavoredParamAndArg(CS, secondParamTy, secondArgTy, firstArgTy)) &&
931931
firstParamTy->isEqual(secondParamTy) &&
932932
(!contextualTy || contextualTy->isEqual(resultTy));
933933
};
@@ -1083,7 +1083,7 @@ namespace {
10831083
auto keyTy = dictTy->first;
10841084
auto valueTy = dictTy->second;
10851085

1086-
if (isFavoredParamAndArg(CS, keyTy, index, index->getType())) {
1086+
if (isFavoredParamAndArg(CS, keyTy, index->getType(), Type())) {
10871087
outputTy = OptionalType::get(valueTy);
10881088

10891089
if (isLValueBase)
@@ -1164,7 +1164,10 @@ namespace {
11641164

11651165
auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr),
11661166
TVO_PrefersSubtypeBinding);
1167-
CS.addConstraint(ConstraintKind::LiteralConformsTo, tv,
1167+
1168+
tv->getImpl().literalConformanceProto = protocol;
1169+
1170+
CS.addConstraint(ConstraintKind::ConformsTo, tv,
11681171
protocol->getDeclaredType(),
11691172
CS.getConstraintLocator(expr));
11701173
return tv;
@@ -1187,7 +1190,8 @@ namespace {
11871190
// ExpressibleByStringInterpolation protocol.
11881191
auto locator = CS.getConstraintLocator(expr);
11891192
auto tv = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding);
1190-
CS.addConstraint(ConstraintKind::LiteralConformsTo, tv,
1193+
tv->getImpl().literalConformanceProto = interpolationProto;
1194+
CS.addConstraint(ConstraintKind::ConformsTo, tv,
11911195
interpolationProto->getDeclaredType(),
11921196
locator);
11931197

@@ -1260,7 +1264,9 @@ namespace {
12601264
auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr),
12611265
TVO_PrefersSubtypeBinding);
12621266

1263-
CS.addConstraint(ConstraintKind::LiteralConformsTo, tv,
1267+
tv->getImpl().literalConformanceProto = protocol;
1268+
1269+
CS.addConstraint(ConstraintKind::ConformsTo, tv,
12641270
protocol->getDeclaredType(),
12651271
CS.getConstraintLocator(expr));
12661272

@@ -1677,7 +1683,7 @@ namespace {
16771683
contextualArrayElementType =
16781684
CS.getBaseTypeForArrayType(contextualType.getPointer());
16791685

1680-
CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType,
1686+
CS.addConstraint(ConstraintKind::ConformsTo, contextualType,
16811687
arrayProto->getDeclaredType(),
16821688
locator);
16831689

@@ -1697,7 +1703,7 @@ namespace {
16971703
auto arrayTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding);
16981704

16991705
// The array must be an array literal type.
1700-
CS.addConstraint(ConstraintKind::LiteralConformsTo, arrayTy,
1706+
CS.addConstraint(ConstraintKind::ConformsTo, arrayTy,
17011707
arrayProto->getDeclaredType(),
17021708
locator);
17031709

@@ -1763,8 +1769,8 @@ namespace {
17631769
auto dictionaryTy = CS.createTypeVariable(locator,
17641770
TVO_PrefersSubtypeBinding);
17651771

1766-
// The dictionary must be a dictionary literal type.
1767-
CS.addConstraint(ConstraintKind::LiteralConformsTo, dictionaryTy,
1772+
// The array must be a dictionary literal type.
1773+
CS.addConstraint(ConstraintKind::ConformsTo, dictionaryTy,
17681774
dictionaryProto->getDeclaredType(),
17691775
locator);
17701776

lib/Sema/CSSimplify.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,7 +2288,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
22882288
return SolutionKind::Solved;
22892289
break;
22902290
case ConstraintKind::ConformsTo:
2291-
case ConstraintKind::LiteralConformsTo:
22922291
// Check whether this type conforms to the protocol.
22932292
if (TC.conformsToProtocol(type, protocol, DC,
22942293
ConformanceCheckFlags::InExpression))
@@ -3468,7 +3467,6 @@ static TypeMatchKind getTypeMatchKind(ConstraintKind kind) {
34683467
llvm_unreachable("Overload binding constraints don't involve type matches");
34693468

34703469
case ConstraintKind::ConformsTo:
3471-
case ConstraintKind::LiteralConformsTo:
34723470
case ConstraintKind::SelfObjectOfProtocol:
34733471
llvm_unreachable("Conformance constraints don't involve type matches");
34743472

@@ -4128,7 +4126,6 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
41284126
return SolutionKind::Solved;
41294127

41304128
case ConstraintKind::ConformsTo:
4131-
case ConstraintKind::LiteralConformsTo:
41324129
case ConstraintKind::SelfObjectOfProtocol:
41334130
return simplifyConformsToConstraint(
41344131
constraint.getFirstType(),

lib/Sema/CSSolver.cpp

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -62,24 +62,14 @@ static Optional<Type> checkTypeOfBinding(ConstraintSystem &cs,
6262
return None;
6363

6464
// If the type is a type variable itself, don't permit the binding.
65+
// FIXME: This is a hack. We need to be smarter about whether there's enough
66+
// structure in the type to produce an interesting binding, or not.
6567
if (auto bindingTypeVar = type->getRValueType()->getAs<TypeVariableType>()) {
66-
if (isNilLiteral) {
67-
*isNilLiteral = false;
68-
69-
// Look for a literal-conformance constraint on the type variable.
70-
SmallVector<Constraint *, 8> constraints;
71-
cs.getConstraintGraph().gatherConstraints(bindingTypeVar, constraints);
72-
for (auto constraint : constraints) {
73-
if (constraint->getKind() == ConstraintKind::LiteralConformsTo &&
74-
constraint->getProtocol()->isSpecificProtocol(
75-
KnownProtocolKind::ExpressibleByNilLiteral) &&
76-
cs.simplifyType(constraint->getFirstType())
77-
->isEqual(bindingTypeVar)) {
78-
*isNilLiteral = true;
79-
break;
80-
}
81-
}
82-
}
68+
if (isNilLiteral &&
69+
bindingTypeVar->getImpl().literalConformanceProto &&
70+
bindingTypeVar->getImpl().literalConformanceProto->isSpecificProtocol(
71+
KnownProtocolKind::ExpressibleByNilLiteral))
72+
*isNilLiteral = true;
8373

8474
return None;
8575
}
@@ -677,7 +667,6 @@ static bool shouldBindToValueType(Constraint *constraint)
677667
case ConstraintKind::Equal:
678668
case ConstraintKind::BindParam:
679669
case ConstraintKind::ConformsTo:
680-
case ConstraintKind::LiteralConformsTo:
681670
case ConstraintKind::CheckedCast:
682671
case ConstraintKind::SelfObjectOfProtocol:
683672
case ConstraintKind::ApplicableFunction:
@@ -793,19 +782,8 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
793782
result.InvolvesTypeVariables = true;
794783
continue;
795784

796-
case ConstraintKind::LiteralConformsTo:
797-
// If there is a 'nil' literal constraint, we might need optional
798-
// supertype bindings.
799-
if (constraint->getProtocol()->isSpecificProtocol(
800-
KnownProtocolKind::ExpressibleByNilLiteral))
801-
addOptionalSupertypeBindings = true;
802-
803-
SWIFT_FALLTHROUGH;
804-
805-
case ConstraintKind::ConformsTo:
785+
case ConstraintKind::ConformsTo:
806786
case ConstraintKind::SelfObjectOfProtocol: {
807-
// FIXME: Only for LiteralConformsTo?
808-
809787
// If there is a default literal type for this protocol, it's a
810788
// potential binding.
811789
auto defaultType = tc.getDefaultType(constraint->getProtocol(), cs.DC);
@@ -930,17 +908,13 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs,
930908
// Check whether we can perform this binding.
931909
// FIXME: this has a super-inefficient extraneous simplifyType() in it.
932910
bool isNilLiteral = false;
933-
bool *isNilLiteralPtr = nullptr;
934-
if (!addOptionalSupertypeBindings && kind == AllowedBindingKind::Supertypes)
935-
isNilLiteralPtr = &isNilLiteral;
936-
if (auto boundType = checkTypeOfBinding(cs, typeVar, type,
937-
isNilLiteralPtr)) {
911+
if (auto boundType = checkTypeOfBinding(cs, typeVar, type, &isNilLiteral)) {
938912
type = *boundType;
939913
if (type->hasTypeVariable())
940914
result.InvolvesTypeVariables = true;
941915
} else {
942916
// If the bound is a 'nil' literal type, add optional supertype bindings.
943-
if (isNilLiteral) {
917+
if (isNilLiteral && kind == AllowedBindingKind::Supertypes) {
944918
addOptionalSupertypeBindings = true;
945919
continue;
946920
}

lib/Sema/Constraint.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
6161
case ConstraintKind::OperatorArgumentTupleConversion:
6262
case ConstraintKind::OperatorArgumentConversion:
6363
case ConstraintKind::ConformsTo:
64-
case ConstraintKind::LiteralConformsTo:
6564
case ConstraintKind::CheckedCast:
6665
case ConstraintKind::SelfObjectOfProtocol:
6766
case ConstraintKind::DynamicTypeOf:
@@ -145,7 +144,6 @@ Constraint::Constraint(ConstraintKind kind, Fix fix,
145144

146145
ProtocolDecl *Constraint::getProtocol() const {
147146
assert((Kind == ConstraintKind::ConformsTo ||
148-
Kind == ConstraintKind::LiteralConformsTo ||
149147
Kind == ConstraintKind::SelfObjectOfProtocol)
150148
&& "Not a conformance constraint");
151149
return Types.Second->castTo<ProtocolType>()->getDecl();
@@ -164,7 +162,6 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
164162
case ConstraintKind::OperatorArgumentTupleConversion:
165163
case ConstraintKind::OperatorArgumentConversion:
166164
case ConstraintKind::ConformsTo:
167-
case ConstraintKind::LiteralConformsTo:
168165
case ConstraintKind::CheckedCast:
169166
case ConstraintKind::DynamicTypeOf:
170167
case ConstraintKind::SelfObjectOfProtocol:
@@ -241,7 +238,6 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
241238
case ConstraintKind::OperatorArgumentConversion:
242239
Out << " operator arg conv "; break;
243240
case ConstraintKind::ConformsTo: Out << " conforms to "; break;
244-
case ConstraintKind::LiteralConformsTo: Out << " literal conforms to "; break;
245241
case ConstraintKind::CheckedCast: Out << " checked cast to "; break;
246242
case ConstraintKind::SelfObjectOfProtocol: Out << " Self type of "; break;
247243
case ConstraintKind::ApplicableFunction: Out << " applicable fn "; break;
@@ -490,7 +486,6 @@ gatherReferencedTypeVars(Constraint *constraint,
490486
case ConstraintKind::BindOverload:
491487
case ConstraintKind::Class:
492488
case ConstraintKind::ConformsTo:
493-
case ConstraintKind::LiteralConformsTo:
494489
case ConstraintKind::SelfObjectOfProtocol:
495490
constraint->getFirstType()->getTypeVariables(typeVars);
496491

lib/Sema/Constraint.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,6 @@ enum class ConstraintKind : char {
8181
/// \brief The first type must conform to the second type (which is a
8282
/// protocol type).
8383
ConformsTo,
84-
/// \brief The first type describes a literal that conforms to the second
85-
/// type, which is one of the known expressible-by-literal protocols.
86-
LiteralConformsTo,
8784
/// A checked cast from the first type to the second.
8885
CheckedCast,
8986
/// \brief The first type can act as the Self type of the second type (which
@@ -476,7 +473,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
476473
case ConstraintKind::OperatorArgumentTupleConversion:
477474
case ConstraintKind::OperatorArgumentConversion:
478475
case ConstraintKind::ConformsTo:
479-
case ConstraintKind::LiteralConformsTo:
480476
case ConstraintKind::CheckedCast:
481477
case ConstraintKind::SelfObjectOfProtocol:
482478
case ConstraintKind::ApplicableFunction:

lib/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ class TypeVariableType::Implementation {
158158
friend class constraints::SavedTypeVariableBinding;
159159

160160
public:
161+
162+
/// \brief If this type variable is an opened literal expression, keep track
163+
/// of the associated literal conformance for optimization and diagnostic
164+
/// purposes.
165+
ProtocolDecl *literalConformanceProto = nullptr;
166+
161167
explicit Implementation(constraints::ConstraintLocator *locator,
162168
unsigned options)
163169
: Options(options), locator(locator),

0 commit comments

Comments
 (0)