Skip to content

Commit ba1c548

Browse files
authored
Merge pull request swiftlang#38082 from hborla/tuple-locator-refactoring
[ConstraintSystem] Store tuple types in the locator when matching element types.
2 parents 973cd73 + db3066d commit ba1c548

File tree

8 files changed

+66
-18
lines changed

8 files changed

+66
-18
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,20 @@ class LocatorPathElt::SynthesizedArgument final : public StoredIntegerElement<2>
581581
}
582582
};
583583

584+
class LocatorPathElt::TupleType : public StoredPointerElement<TypeBase> {
585+
public:
586+
TupleType(Type type)
587+
: StoredPointerElement(PathElementKind::TupleType, type.getPointer()) {
588+
assert(type->getDesugaredType()->is<swift::TupleType>());
589+
}
590+
591+
Type getType() const { return getStoredPointer(); }
592+
593+
static bool classof(const LocatorPathElt *elt) {
594+
return elt->getKind() == PathElementKind::TupleType;
595+
}
596+
};
597+
584598
/// Abstract superclass for any kind of tuple element.
585599
class LocatorPathElt::AnyTupleElement : public StoredIntegerElement<1> {
586600
protected:

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ SIMPLE_LOCATOR_PATH_ELT(SubscriptMember)
164164
/// The missing argument synthesized by the solver.
165165
CUSTOM_LOCATOR_PATH_ELT(SynthesizedArgument)
166166

167+
/// A tuple type, which provides context for subsequent tuple element
168+
/// path components.
169+
CUSTOM_LOCATOR_PATH_ELT(TupleType)
170+
167171
/// Tuple elements.
168172
ABSTRACT_LOCATOR_PATH_ELT(AnyTupleElement)
169173
/// A tuple element referenced by position.

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3177,7 +3177,7 @@ bool TupleContextualFailure::diagnoseAsError() {
31773177
auto purpose = getContextualTypePurpose();
31783178
if (isNumElementsMismatch())
31793179
diagnostic = diag::tuple_types_not_convertible_nelts;
3180-
else if ((purpose == CTP_Initialization) && !getContextualType(getAnchor()))
3180+
else if (purpose == CTP_Unused)
31813181
diagnostic = diag::tuple_types_not_convertible;
31823182
else if (auto diag = getDiagnosticFor(purpose, getToType()))
31833183
diagnostic = *diag;

lib/Sema/CSFix.cpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -453,26 +453,19 @@ bool AllowTupleTypeMismatch::coalesceAndDiagnose(
453453
indices.push_back(*tupleFix->Index);
454454
}
455455

456-
auto &cs = getConstraintSystem();
457456
auto *locator = getLocator();
458457
ContextualTypePurpose purpose;
459-
Type fromType;
460-
Type toType;
461-
462-
if (getFromType()->is<TupleType>() && getToType()->is<TupleType>()) {
463-
purpose = cs.getContextualTypePurpose(locator->getAnchor());
464-
fromType = getFromType();
465-
toType = getToType();
466-
} else if (auto contextualTypeInfo =
467-
getStructuralTypeContext(solution, locator)) {
468-
std::tie(purpose, fromType, toType) = *contextualTypeInfo;
458+
if (isExpr<CoerceExpr>(locator->getAnchor())) {
459+
purpose = CTP_CoerceOperand;
460+
} else if (auto *assignExpr = getAsExpr<AssignExpr>(locator->getAnchor())) {
461+
purpose = isa<SubscriptExpr>(assignExpr->getDest()) ? CTP_SubscriptAssignSource
462+
: CTP_AssignSource;
469463
} else {
470-
return false;
464+
auto &cs = getConstraintSystem();
465+
purpose = cs.getContextualTypePurpose(locator->getAnchor());
471466
}
472467

473-
TupleContextualFailure failure(solution, purpose,
474-
fromType->lookThroughAllOptionalTypes(),
475-
toType->lookThroughAllOptionalTypes(),
468+
TupleContextualFailure failure(solution, purpose, getFromType(), getToType(),
476469
indices, locator);
477470
return failure.diagnose(asNote);
478471
}

lib/Sema/CSSimplify.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,9 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
15471547
SmallVector<LocatorPathElt, 4> path;
15481548
(void)locator.getLocatorParts(path);
15491549

1550+
while (!path.empty() && path.back().is<LocatorPathElt::TupleType>())
1551+
path.pop_back();
1552+
15501553
if (!path.empty()) {
15511554
// Direct pattern matching between tuple pattern and tuple type.
15521555
if (path.back().is<LocatorPathElt::PatternMatch>()) {
@@ -4723,6 +4726,15 @@ bool ConstraintSystem::repairFailures(
47234726
// mismatches within the same tuple type can be coalesced later.
47244727
auto index = elt.getAs<LocatorPathElt::TupleElement>()->getIndex();
47254728
path.pop_back();
4729+
4730+
// Drop the tuple type path elements too, but extract each tuple type first.
4731+
if (path.back().is<LocatorPathElt::TupleType>()) {
4732+
rhs = path.back().getAs<LocatorPathElt::TupleType>()->getType();
4733+
path.pop_back();
4734+
lhs = path.back().getAs<LocatorPathElt::TupleType>()->getType();
4735+
path.pop_back();
4736+
}
4737+
47264738
auto *tupleLocator = getConstraintLocator(locator.getAnchor(), path);
47274739

47284740
// Let this fail if it's a contextual mismatch with sequence element types,
@@ -5225,9 +5237,15 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
52255237
}
52265238

52275239
case TypeKind::Tuple: {
5240+
// Add each tuple type to the locator before matching the element types.
5241+
// This is useful for diagnostics, because the error message can use the
5242+
// full tuple type for several element mismatches. Use the original types
5243+
// to preserve sugar such as typealiases.
5244+
auto tmpTupleLoc = locator.withPathElement(LocatorPathElt::TupleType(type1));
5245+
auto tupleLoc = tmpTupleLoc.withPathElement(LocatorPathElt::TupleType(type2));
52285246
auto result = matchTupleTypes(cast<TupleType>(desugar1),
52295247
cast<TupleType>(desugar2),
5230-
kind, subflags, locator);
5248+
kind, subflags, tupleLoc);
52315249
if (result != SolutionKind::Error)
52325250
return result;
52335251

lib/Sema/ConstraintLocator.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
6363
case ConstraintLocator::WrappedValue:
6464
case ConstraintLocator::GenericParameter:
6565
case ConstraintLocator::GenericArgument:
66+
case ConstraintLocator::TupleType:
6667
case ConstraintLocator::NamedTupleElement:
6768
case ConstraintLocator::TupleElement:
6869
case ConstraintLocator::ProtocolRequirement:
@@ -356,6 +357,12 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
356357
out << "member reference base";
357358
break;
358359

360+
case TupleType: {
361+
auto tupleElt = elt.castTo<LocatorPathElt::TupleType>();
362+
out << "tuple type '" << tupleElt.getType()->getString(PO) << "'";
363+
break;
364+
}
365+
359366
case NamedTupleElement: {
360367
auto tupleElt = elt.castTo<LocatorPathElt::NamedTupleElement>();
361368
out << "named tuple element #" << llvm::utostr(tupleElt.getIndex());

lib/Sema/ConstraintSystem.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4273,6 +4273,10 @@ void constraints::simplifyLocator(ASTNode &anchor,
42734273
path = path.slice(1);
42744274
continue;
42754275

4276+
case ConstraintLocator::TupleType:
4277+
path = path.slice(1);
4278+
continue;
4279+
42764280
case ConstraintLocator::NamedTupleElement:
42774281
case ConstraintLocator::TupleElement: {
42784282
// Extract tuple element.

test/Constraints/diagnostics.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,17 @@ func r22263468(_ a : String?) {
573573
// TODO(diagnostics): This is a regression from diagnosing missing optional unwrap for `a`, we have to
574574
// re-think the way errors in tuple elements are detected because it's currently impossible to detect
575575
// exactly what went wrong here and aggregate fixes for different elements at the same time.
576-
_ = MyTuple(42, a) // expected-error {{tuple type 'MyTuple' (aka '(Int, String)') is not convertible to tuple type '(Int, String?)'}}
576+
_ = MyTuple(42, a) // expected-error {{tuple type '(Int, String?)' is not convertible to tuple type 'MyTuple' (aka '(Int, String)')}}
577577
}
578578

579+
// rdar://71829040 - "ambiguous without more context" error for tuple type mismatch.
580+
func r71829040() {
581+
func object(forKey: String) -> Any? { nil }
582+
583+
let flags: [String: String]
584+
// expected-error@+1 {{tuple type '(String, Bool)' is not convertible to tuple type '(String, String)'}}
585+
flags = Dictionary(uniqueKeysWithValues: ["keyA", "keyB"].map { ($0, object(forKey: $0) as? Bool ?? false) })
586+
}
579587

580588
// rdar://22470302 - Crash with parenthesized call result.
581589
class r22470302Class {

0 commit comments

Comments
 (0)