Skip to content

Commit 371d800

Browse files
committed
Merge remote-tracking branch 'origin/main' into next
2 parents 3a52c8c + f10d0df commit 371d800

File tree

10 files changed

+118
-29
lines changed

10 files changed

+118
-29
lines changed

include/swift/Sema/CSFix.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ enum class FixKind : uint8_t {
306306
/// This issue should already have been diagnosed elsewhere.
307307
IgnoreUnresolvedPatternVar,
308308

309+
/// Ignore a nested UnresolvedPatternExpr in an ExprPattern, which is invalid.
310+
IgnoreInvalidPatternInExpr,
311+
309312
/// Resolve type of `nil` by providing a contextual type.
310313
SpecifyContextualTypeForNil,
311314

@@ -2963,6 +2966,33 @@ class IgnoreUnresolvedPatternVar final : public ConstraintFix {
29632966
}
29642967
};
29652968

2969+
class IgnoreInvalidPatternInExpr final : public ConstraintFix {
2970+
Pattern *P;
2971+
2972+
IgnoreInvalidPatternInExpr(ConstraintSystem &cs, Pattern *pattern,
2973+
ConstraintLocator *locator)
2974+
: ConstraintFix(cs, FixKind::IgnoreInvalidPatternInExpr, locator),
2975+
P(pattern) {}
2976+
2977+
public:
2978+
std::string getName() const override {
2979+
return "ignore invalid Pattern nested in Expr";
2980+
}
2981+
2982+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2983+
2984+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
2985+
return diagnose(*commonFixes.front().first);
2986+
}
2987+
2988+
static IgnoreInvalidPatternInExpr *
2989+
create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator);
2990+
2991+
static bool classof(const ConstraintFix *fix) {
2992+
return fix->getKind() == FixKind::IgnoreInvalidPatternInExpr;
2993+
}
2994+
};
2995+
29662996
class SpecifyContextualTypeForNil final : public ConstraintFix {
29672997
SpecifyContextualTypeForNil(ConstraintSystem &cs,
29682998
ConstraintLocator *locator)

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4604,24 +4604,11 @@ namespace {
46044604
Expr *visitDiscardAssignmentExpr(DiscardAssignmentExpr *expr) {
46054605
return simplifyExprType(expr);
46064606
}
4607-
4607+
46084608
Expr *visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) {
4609-
// If we end up here, we should have diagnosed somewhere else
4610-
// already.
4611-
Expr *simplified = simplifyExprType(expr);
4612-
// Invalidate 'VarDecl's inside the pattern.
4613-
expr->getSubPattern()->forEachVariable([](VarDecl *VD) {
4614-
VD->setInvalid();
4615-
});
4616-
if (!SuppressDiagnostics
4617-
&& !cs.getType(simplified)->is<UnresolvedType>()) {
4618-
auto &de = cs.getASTContext().Diags;
4619-
de.diagnose(simplified->getLoc(), diag::pattern_in_expr,
4620-
expr->getSubPattern()->getDescriptiveKind());
4621-
}
4622-
return simplified;
4609+
llvm_unreachable("Should have diagnosed");
46234610
}
4624-
4611+
46254612
Expr *visitBindOptionalExpr(BindOptionalExpr *expr) {
46264613
return simplifyExprType(expr);
46274614
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8295,6 +8295,32 @@ bool InvalidEmptyKeyPathFailure::diagnoseAsError() {
82958295
return true;
82968296
}
82978297

8298+
bool InvalidPatternInExprFailure::diagnoseAsError() {
8299+
// Check to see if we have something like 'case <fn>(let foo)', where <fn>
8300+
// has a fix associated with it. In such a case, it's more likely than not
8301+
// that the user is trying to write an EnumElementPattern, but has made some
8302+
// kind of mistake in the function expr that causes it to be treated as an
8303+
// ExprPattern. Emitting an additional error for the out of place 'let foo' is
8304+
// just noise in that case, so let's avoid diagnosing.
8305+
llvm::SmallPtrSet<Expr *, 4> fixAnchors;
8306+
for (auto *fix : getSolution().Fixes) {
8307+
if (auto *anchor = getAsExpr(fix->getAnchor()))
8308+
fixAnchors.insert(anchor);
8309+
}
8310+
{
8311+
auto *E = castToExpr(getLocator()->getAnchor());
8312+
while (auto *parent = findParentExpr(E)) {
8313+
if (auto *CE = dyn_cast<CallExpr>(parent)) {
8314+
if (fixAnchors.contains(CE->getFn()))
8315+
return false;
8316+
}
8317+
E = parent;
8318+
}
8319+
}
8320+
emitDiagnostic(diag::pattern_in_expr, P->getDescriptiveKind());
8321+
return true;
8322+
}
8323+
82988324
bool MissingContextualTypeForNil::diagnoseAsError() {
82998325
auto *expr = castToExpr<NilLiteralExpr>(getAnchor());
83008326

lib/Sema/CSDiagnostics.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,22 @@ class InvalidEmptyKeyPathFailure final : public FailureDiagnostic {
25312531
bool diagnoseAsError() override;
25322532
};
25332533

2534+
/// Diagnose an invalid Pattern node in an ExprPattern.
2535+
///
2536+
/// \code
2537+
/// if case foo(let x) = y {}
2538+
/// \endcode
2539+
class InvalidPatternInExprFailure final : public FailureDiagnostic {
2540+
Pattern *P;
2541+
2542+
public:
2543+
InvalidPatternInExprFailure(const Solution &solution, Pattern *pattern,
2544+
ConstraintLocator *locator)
2545+
: FailureDiagnostic(solution, locator), P(pattern) {}
2546+
2547+
bool diagnoseAsError() override;
2548+
};
2549+
25342550
/// Diagnose situations where there is no context to determine a
25352551
/// type of `nil` literal e.g.
25362552
///

lib/Sema/CSFix.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,6 +2080,19 @@ IgnoreInvalidASTNode *IgnoreInvalidASTNode::create(ConstraintSystem &cs,
20802080
return new (cs.getAllocator()) IgnoreInvalidASTNode(cs, locator);
20812081
}
20822082

2083+
bool IgnoreInvalidPatternInExpr::diagnose(const Solution &solution,
2084+
bool asNote) const {
2085+
InvalidPatternInExprFailure failure(solution, P, getLocator());
2086+
return failure.diagnose(asNote);
2087+
}
2088+
2089+
IgnoreInvalidPatternInExpr *
2090+
IgnoreInvalidPatternInExpr::create(ConstraintSystem &cs, Pattern *pattern,
2091+
ConstraintLocator *locator) {
2092+
return new (cs.getAllocator())
2093+
IgnoreInvalidPatternInExpr(cs, pattern, locator);
2094+
}
2095+
20832096
bool SpecifyContextualTypeForNil::diagnose(const Solution &solution,
20842097
bool asNote) const {
20852098
MissingContextualTypeForNil failure(solution, getLocator());

lib/Sema/CSGen.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3432,16 +3432,18 @@ namespace {
34323432
}
34333433

34343434
Type visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) {
3435-
// If there are UnresolvedPatterns floating around after pattern type
3436-
// checking, they are definitely invalid. However, we will
3437-
// diagnose that condition elsewhere; to avoid unnecessary noise errors,
3438-
// just plop an open type variable here.
3439-
3440-
auto locator = CS.getConstraintLocator(expr);
3441-
auto typeVar = CS.createTypeVariable(locator,
3442-
TVO_CanBindToLValue |
3443-
TVO_CanBindToNoEscape);
3444-
return typeVar;
3435+
// Encountering an UnresolvedPatternExpr here means we have an invalid
3436+
// ExprPattern with a Pattern node like 'let x' nested in it. Record a
3437+
// fix, and assign ErrorTypes to any VarDecls bound.
3438+
auto *locator = CS.getConstraintLocator(expr);
3439+
auto *P = expr->getSubPattern();
3440+
CS.recordFix(IgnoreInvalidPatternInExpr::create(CS, P, locator));
3441+
3442+
P->forEachVariable([&](VarDecl *VD) {
3443+
CS.setType(VD, ErrorType::get(CS.getASTContext()));
3444+
});
3445+
3446+
return CS.createTypeVariable(locator, TVO_CanBindToHole);
34453447
}
34463448

34473449
/// Get the type T?

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14950,6 +14950,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1495014950
case FixKind::AddExplicitExistentialCoercion:
1495114951
case FixKind::DestructureTupleToMatchPackExpansionParameter:
1495214952
case FixKind::AllowValueExpansionWithoutPackReferences:
14953+
case FixKind::IgnoreInvalidPatternInExpr:
1495314954
case FixKind::IgnoreMissingEachKeyword:
1495414955
llvm_unreachable("handled elsewhere");
1495514956
}

test/Constraints/issue-66553.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// https://github.com/apple/swift/issues/66553
4+
5+
func baz(y: [Int], z: Int) -> Int {
6+
switch z {
7+
case y[let z]: // expected-error {{'let' binding pattern cannot appear in an expression}}
8+
z
9+
default:
10+
z
11+
}
12+
}

test/Constraints/rdar105782480.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func foo(value: MyEnum) {
1212
switch value {
1313
case .second(let drag).invalid:
1414
// expected-error@-1 {{value of type 'MyEnum' has no member 'invalid'}}
15+
// expected-error@-2 {{'let' binding pattern cannot appear in an expression}}
1516
break
1617
}
1718
}

test/Constraints/rdar106598067.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
enum E: Error { case e }
44

55
// rdar://106598067 – Make sure we don't crash.
6-
// FIXME: Bad diagnostic (the issue is that it should be written 'as', not 'as?')
6+
// FIXME: We ought to have a tailored diagnostic to change to 'as' instead of 'as?'
77
let fn = {
8-
// expected-error@-1 {{unable to infer closure type without a type annotation}}
98
do {} catch let x as? E {}
10-
// expected-warning@-1 {{'catch' block is unreachable because no errors are thrown in 'do' block}}
9+
// expected-error@-1 {{pattern variable binding cannot appear in an expression}}
10+
// expected-error@-2 {{expression pattern of type 'E?' cannot match values of type 'any Error'}}
11+
// expected-warning@-3 {{'catch' block is unreachable because no errors are thrown in 'do' block}}
1112
}

0 commit comments

Comments
 (0)