Skip to content

Commit 3087afc

Browse files
authored
Merge pull request swiftlang#65651 from hamishknight/placeholder
Resolves swiftlang#65650
2 parents bd1cc4c + b07f7b3 commit 3087afc

21 files changed

+190
-109
lines changed

include/swift/Sema/CSFix.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ enum class FixKind : uint8_t {
401401
/// Produce a warning for a tuple label mismatch.
402402
AllowTupleLabelMismatch,
403403

404+
/// Allow an associated value mismatch for an enum element pattern.
405+
AllowAssociatedValueMismatch,
406+
404407
/// Produce an error for not getting a compile-time constant
405408
NotCompileTimeConst,
406409

@@ -3238,6 +3241,28 @@ class AllowTupleLabelMismatch final : public ContextualMismatch {
32383241
}
32393242
};
32403243

3244+
class AllowAssociatedValueMismatch final : public ContextualMismatch {
3245+
AllowAssociatedValueMismatch(ConstraintSystem &cs, Type fromType, Type toType,
3246+
ConstraintLocator *locator)
3247+
: ContextualMismatch(cs, FixKind::AllowAssociatedValueMismatch, fromType,
3248+
toType, locator) {}
3249+
3250+
public:
3251+
std::string getName() const override {
3252+
return "allow associated value mismatch";
3253+
}
3254+
3255+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3256+
3257+
static AllowAssociatedValueMismatch *create(ConstraintSystem &cs,
3258+
Type fromType, Type toType,
3259+
ConstraintLocator *locator);
3260+
3261+
static bool classof(const ConstraintFix *fix) {
3262+
return fix->getKind() == FixKind::AllowAssociatedValueMismatch;
3263+
}
3264+
};
3265+
32413266
class AllowNonOptionalWeak final : public ConstraintFix {
32423267
AllowNonOptionalWeak(ConstraintSystem &cs, ConstraintLocator *locator)
32433268
: ConstraintFix(cs, FixKind::AllowNonOptionalWeak, locator) {}

include/swift/Sema/ConstraintLocator.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818
#ifndef SWIFT_SEMA_CONSTRAINTLOCATOR_H
1919
#define SWIFT_SEMA_CONSTRAINTLOCATOR_H
2020

21-
#include "swift/Basic/Debug.h"
22-
#include "swift/Basic/LLVM.h"
2321
#include "swift/AST/ASTNode.h"
2422
#include "swift/AST/Type.h"
2523
#include "swift/AST/Types.h"
24+
#include "swift/Basic/Debug.h"
25+
#include "swift/Basic/LLVM.h"
26+
#include "swift/Basic/NullablePtr.h"
2627
#include "llvm/ADT/ArrayRef.h"
2728
#include "llvm/ADT/FoldingSet.h"
2829
#include "llvm/ADT/PointerIntPair.h"
@@ -313,6 +314,10 @@ class ConstraintLocator : public llvm::FoldingSetNode {
313314
/// branch, and if so, the kind of branch.
314315
Optional<SingleValueStmtBranchKind> isForSingleValueStmtBranch() const;
315316

317+
/// If the locator in question is for a pattern match, returns the pattern,
318+
/// otherwise \c nullptr.
319+
NullablePtr<Pattern> getPatternMatch() const;
320+
316321
/// Returns true if \p locator is ending with either of the following
317322
/// - Member
318323
/// - Member -> KeyPathDynamicMember

lib/AST/ASTContext.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ struct ASTContext::Implementation {
430430
llvm::DenseMap<Type, InOutType*> InOutTypes;
431431
llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
432432
DependentMemberTypes;
433+
llvm::DenseMap<void *, PlaceholderType *> PlaceholderTypes;
433434
llvm::DenseMap<Type, DynamicSelfType *> DynamicSelfTypes;
434435
llvm::DenseMap<std::pair<EnumDecl*, Type>, EnumType*> EnumTypes;
435436
llvm::DenseMap<std::pair<StructDecl*, Type>, StructType*> StructTypes;
@@ -3124,8 +3125,27 @@ Type ErrorType::get(Type originalType) {
31243125

31253126
Type PlaceholderType::get(ASTContext &ctx, Originator originator) {
31263127
assert(originator);
3127-
return new (ctx, AllocationArena::Permanent)
3128+
3129+
auto hasTypeVariables = [&]() -> bool {
3130+
if (originator.is<TypeVariableType *>())
3131+
return true;
3132+
3133+
if (auto *depTy = originator.dyn_cast<DependentMemberType *>())
3134+
return depTy->hasTypeVariable();
3135+
3136+
return false;
3137+
}();
3138+
auto arena = hasTypeVariables ? AllocationArena::ConstraintSolver
3139+
: AllocationArena::Permanent;
3140+
3141+
auto &cache = ctx.getImpl().getArena(arena).PlaceholderTypes;
3142+
auto &entry = cache[originator.getOpaqueValue()];
3143+
if (entry)
3144+
return entry;
3145+
3146+
entry = new (ctx, arena)
31283147
PlaceholderType(ctx, originator, RecursiveTypeProperties::HasPlaceholder);
3148+
return entry;
31293149
}
31303150

31313151
BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,

lib/Sema/CSBindings.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,16 +2203,25 @@ TypeVariableBinding::fixForHole(ConstraintSystem &cs) const {
22032203
return std::make_pair(fix, /*impact=*/(unsigned)10);
22042204
}
22052205

2206-
if (auto pattern = getAsPattern(dstLocator->getAnchor())) {
2207-
if (dstLocator->getPath().size() == 1 &&
2208-
dstLocator->isLastElement<LocatorPathElt::PatternDecl>()) {
2206+
if (auto pattern = dstLocator->getPatternMatch()) {
2207+
if (dstLocator->isLastElement<LocatorPathElt::PatternDecl>()) {
2208+
// If this is the pattern in a for loop, and we have a mismatch of the
2209+
// element type, then we don't have any useful contextual information
2210+
// for the pattern, and can just bind to a hole without needing to penalize
2211+
// the solution further.
2212+
auto *seqLoc = cs.getConstraintLocator(
2213+
dstLocator->getAnchor(), ConstraintLocator::SequenceElementType);
2214+
if (cs.hasFixFor(seqLoc,
2215+
FixKind::IgnoreCollectionElementContextualMismatch)) {
2216+
return None;
2217+
}
22092218
// Not being able to infer the type of a variable in a pattern binding
22102219
// decl is more dramatic than anything that could happen inside the
22112220
// expression because we want to preferrably point the diagnostic to a
22122221
// part of the expression that caused us to be unable to infer the
22132222
// variable's type.
22142223
ConstraintFix *fix =
2215-
IgnoreUnresolvedPatternVar::create(cs, pattern, dstLocator);
2224+
IgnoreUnresolvedPatternVar::create(cs, pattern.get(), dstLocator);
22162225
return std::make_pair(fix, /*impact=*/(unsigned)100);
22172226
}
22182227
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,10 @@ bool MissingConformanceFailure::diagnoseAsError() {
513513
llvm::SmallPtrSet<Expr *, 4> anchors;
514514
for (const auto *fix : getSolution().Fixes) {
515515
if (auto anchor = fix->getAnchor()) {
516-
if (anchor.is<Expr *>())
516+
auto path = fix->getLocator()->getPath();
517+
SourceRange range;
518+
simplifyLocator(anchor, path, range);
519+
if (anchor && anchor.is<Expr *>())
517520
anchors.insert(getAsExpr(anchor));
518521
}
519522
}
@@ -654,10 +657,15 @@ bool MissingConformanceFailure::diagnoseAsAmbiguousOperatorRef() {
654657
if (!ODRE)
655658
return false;
656659

660+
auto isStandardType = [](Type ty) {
661+
return ty->isStdlibType() || ty->is<TupleType>();
662+
};
663+
657664
auto name = ODRE->getDecls().front()->getBaseName();
658-
if (!(name.isOperator() && getLHS()->isStdlibType() && getRHS()->isStdlibType()))
665+
if (!(name.isOperator() && isStandardType(getLHS()) &&
666+
isStandardType(getRHS()))) {
659667
return false;
660-
668+
}
661669
// If this is an operator reference and both types are from stdlib,
662670
// let's produce a generic diagnostic about invocation and a note
663671
// about missing conformance just in case.
@@ -2448,9 +2456,6 @@ bool ContextualFailure::diagnoseAsError() {
24482456
return false;
24492457
}
24502458

2451-
if (diagnoseExtraneousAssociatedValues())
2452-
return true;
2453-
24542459
// Special case of some common conversions involving Swift.String
24552460
// indexes, catching cases where people attempt to index them with an integer.
24562461
if (isIntegerToStringIndexConversion()) {
@@ -2891,24 +2896,6 @@ void ContextualFailure::tryFixIts(InFlightDiagnostic &diagnostic) const {
28912896
return;
28922897
}
28932898

2894-
bool ContextualFailure::diagnoseExtraneousAssociatedValues() const {
2895-
if (auto match =
2896-
getLocator()->getLastElementAs<LocatorPathElt::PatternMatch>()) {
2897-
if (auto enumElementPattern =
2898-
dyn_cast<EnumElementPattern>(match->getPattern())) {
2899-
emitDiagnosticAt(enumElementPattern->getNameLoc(),
2900-
diag::enum_element_pattern_assoc_values_mismatch,
2901-
enumElementPattern->getName());
2902-
emitDiagnosticAt(enumElementPattern->getNameLoc(),
2903-
diag::enum_element_pattern_assoc_values_remove)
2904-
.fixItRemove(enumElementPattern->getSubPattern()->getSourceRange());
2905-
return true;
2906-
}
2907-
}
2908-
2909-
return false;
2910-
}
2911-
29122899
bool ContextualFailure::diagnoseCoercionToUnrelatedType() const {
29132900
auto anchor = getRawAnchor();
29142901
auto *coerceExpr = getAsExpr<CoerceExpr>(anchor);
@@ -8684,6 +8671,19 @@ bool TupleLabelMismatchWarning::diagnoseAsError() {
86848671
return true;
86858672
}
86868673

8674+
bool AssociatedValueMismatchFailure::diagnoseAsError() {
8675+
auto match = getLocator()->castLastElementTo<LocatorPathElt::PatternMatch>();
8676+
auto *enumElementPattern = dyn_cast<EnumElementPattern>(match.getPattern());
8677+
8678+
emitDiagnosticAt(enumElementPattern->getNameLoc(),
8679+
diag::enum_element_pattern_assoc_values_mismatch,
8680+
enumElementPattern->getName());
8681+
emitDiagnosticAt(enumElementPattern->getNameLoc(),
8682+
diag::enum_element_pattern_assoc_values_remove)
8683+
.fixItRemove(enumElementPattern->getSubPattern()->getSourceRange());
8684+
return true;
8685+
}
8686+
86878687
bool SwiftToCPointerConversionInInvalidContext::diagnoseAsError() {
86888688
auto argInfo = getFunctionArgApplyInfo(getLocator());
86898689
if (!argInfo)

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -715,10 +715,6 @@ class ContextualFailure : public FailureDiagnostic {
715715
/// Diagnose failed conversion in a `CoerceExpr`.
716716
bool diagnoseCoercionToUnrelatedType() const;
717717

718-
/// Diagnose cases where a pattern tried to match associated values but
719-
/// the enum case had none.
720-
bool diagnoseExtraneousAssociatedValues() const;
721-
722718
/// Produce a specialized diagnostic if this is an invalid conversion to Bool.
723719
bool diagnoseConversionToBool() const;
724720

@@ -2813,6 +2809,15 @@ class TupleLabelMismatchWarning final : public ContextualFailure {
28132809
bool diagnoseAsError() override;
28142810
};
28152811

2812+
class AssociatedValueMismatchFailure final : public ContextualFailure {
2813+
public:
2814+
AssociatedValueMismatchFailure(const Solution &solution, Type fromType,
2815+
Type toType, ConstraintLocator *locator)
2816+
: ContextualFailure(solution, fromType, toType, locator) {}
2817+
2818+
bool diagnoseAsError() override;
2819+
};
2820+
28162821
/// Diagnose situations where Swift -> C pointer implicit conversion
28172822
/// is attempted on a Swift function instead of one imported from C header.
28182823
///

lib/Sema/CSFix.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,9 +2139,10 @@ IgnoreResultBuilderWithReturnStmts::create(ConstraintSystem &cs, Type builderTy,
21392139

21402140
bool IgnoreUnresolvedPatternVar::diagnose(const Solution &solution,
21412141
bool asNote) const {
2142-
// Not being able to infer the type of a pattern should already have been
2143-
// diagnosed on the pattern's initializer or as a structural issue of the AST.
2144-
return true;
2142+
// An unresolved AnyPatternDecl means there was some issue in the match
2143+
// that means we couldn't infer the pattern. We don't have a diagnostic to
2144+
// emit here, the failure should be diagnosed by the fix for expression.
2145+
return false;
21452146
}
21462147

21472148
IgnoreUnresolvedPatternVar *
@@ -2426,6 +2427,20 @@ bool AllowTupleLabelMismatch::diagnose(const Solution &solution,
24262427
return warning.diagnose(asNote);
24272428
}
24282429

2430+
AllowAssociatedValueMismatch *
2431+
AllowAssociatedValueMismatch::create(ConstraintSystem &cs, Type fromType,
2432+
Type toType, ConstraintLocator *locator) {
2433+
return new (cs.getAllocator())
2434+
AllowAssociatedValueMismatch(cs, fromType, toType, locator);
2435+
}
2436+
2437+
bool AllowAssociatedValueMismatch::diagnose(const Solution &solution,
2438+
bool asNote) const {
2439+
AssociatedValueMismatchFailure failure(solution, getFromType(), getToType(),
2440+
getLocator());
2441+
return failure.diagnose(asNote);
2442+
}
2443+
24292444
bool AllowSwiftToCPointerConversion::diagnose(const Solution &solution,
24302445
bool asNote) const {
24312446
SwiftToCPointerConversionInInvalidContext failure(solution, getLocator());

lib/Sema/CSGen.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,6 +2471,9 @@ namespace {
24712471
: nullptr;
24722472
};
24732473

2474+
auto matchLoc =
2475+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern));
2476+
24742477
// Always prefer a contextual type when it's available.
24752478
if (externalPatternType) {
24762479
type = externalPatternType;
@@ -2479,8 +2482,8 @@ namespace {
24792482
type = CS.getType(initializer)->getRValueType();
24802483
} else {
24812484
type = CS.createTypeVariable(
2482-
CS.getConstraintLocator(pattern,
2483-
ConstraintLocator::AnyPatternDecl),
2485+
CS.getConstraintLocator(matchLoc,
2486+
LocatorPathElt::AnyPatternDecl()),
24842487
TVO_CanBindToNoEscape | TVO_CanBindToHole);
24852488
}
24862489
return setType(type);
@@ -2515,9 +2518,12 @@ namespace {
25152518
}
25162519
}
25172520

2521+
auto matchLoc =
2522+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern));
2523+
25182524
if (!varType) {
25192525
varType = CS.createTypeVariable(
2520-
CS.getConstraintLocator(pattern,
2526+
CS.getConstraintLocator(matchLoc,
25212527
LocatorPathElt::NamedPatternDecl()),
25222528
TVO_CanBindToNoEscape | TVO_CanBindToHole);
25232529

0 commit comments

Comments
 (0)