Skip to content

Commit a00e181

Browse files
authored
Merge pull request #66710 from hamishknight/pattern-error-5.9
2 parents 4ed65f8 + b284b3a commit a00e181

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

@@ -2959,6 +2962,33 @@ class IgnoreUnresolvedPatternVar final : public ConstraintFix {
29592962
}
29602963
};
29612964

2965+
class IgnoreInvalidPatternInExpr final : public ConstraintFix {
2966+
Pattern *P;
2967+
2968+
IgnoreInvalidPatternInExpr(ConstraintSystem &cs, Pattern *pattern,
2969+
ConstraintLocator *locator)
2970+
: ConstraintFix(cs, FixKind::IgnoreInvalidPatternInExpr, locator),
2971+
P(pattern) {}
2972+
2973+
public:
2974+
std::string getName() const override {
2975+
return "ignore invalid Pattern nested in Expr";
2976+
}
2977+
2978+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2979+
2980+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
2981+
return diagnose(*commonFixes.front().first);
2982+
}
2983+
2984+
static IgnoreInvalidPatternInExpr *
2985+
create(ConstraintSystem &cs, Pattern *pattern, ConstraintLocator *locator);
2986+
2987+
static bool classof(const ConstraintFix *fix) {
2988+
return fix->getKind() == FixKind::IgnoreInvalidPatternInExpr;
2989+
}
2990+
};
2991+
29622992
class SpecifyContextualTypeForNil final : public ConstraintFix {
29632993
SpecifyContextualTypeForNil(ConstraintSystem &cs,
29642994
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
@@ -8236,6 +8236,32 @@ bool InvalidEmptyKeyPathFailure::diagnoseAsError() {
82368236
return true;
82378237
}
82388238

8239+
bool InvalidPatternInExprFailure::diagnoseAsError() {
8240+
// Check to see if we have something like 'case <fn>(let foo)', where <fn>
8241+
// has a fix associated with it. In such a case, it's more likely than not
8242+
// that the user is trying to write an EnumElementPattern, but has made some
8243+
// kind of mistake in the function expr that causes it to be treated as an
8244+
// ExprPattern. Emitting an additional error for the out of place 'let foo' is
8245+
// just noise in that case, so let's avoid diagnosing.
8246+
llvm::SmallPtrSet<Expr *, 4> fixAnchors;
8247+
for (auto *fix : getSolution().Fixes) {
8248+
if (auto *anchor = getAsExpr(fix->getAnchor()))
8249+
fixAnchors.insert(anchor);
8250+
}
8251+
{
8252+
auto *E = castToExpr(getLocator()->getAnchor());
8253+
while (auto *parent = findParentExpr(E)) {
8254+
if (auto *CE = dyn_cast<CallExpr>(parent)) {
8255+
if (fixAnchors.contains(CE->getFn()))
8256+
return false;
8257+
}
8258+
E = parent;
8259+
}
8260+
}
8261+
emitDiagnostic(diag::pattern_in_expr, P->getDescriptiveKind());
8262+
return true;
8263+
}
8264+
82398265
bool MissingContextualTypeForNil::diagnoseAsError() {
82408266
auto *expr = castToExpr<NilLiteralExpr>(getAnchor());
82418267

lib/Sema/CSDiagnostics.h

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

2521+
/// Diagnose an invalid Pattern node in an ExprPattern.
2522+
///
2523+
/// \code
2524+
/// if case foo(let x) = y {}
2525+
/// \endcode
2526+
class InvalidPatternInExprFailure final : public FailureDiagnostic {
2527+
Pattern *P;
2528+
2529+
public:
2530+
InvalidPatternInExprFailure(const Solution &solution, Pattern *pattern,
2531+
ConstraintLocator *locator)
2532+
: FailureDiagnostic(solution, locator), P(pattern) {}
2533+
2534+
bool diagnoseAsError() override;
2535+
};
2536+
25212537
/// Diagnose situations where there is no context to determine a
25222538
/// type of `nil` literal e.g.
25232539
///

lib/Sema/CSFix.cpp

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

2091+
bool IgnoreInvalidPatternInExpr::diagnose(const Solution &solution,
2092+
bool asNote) const {
2093+
InvalidPatternInExprFailure failure(solution, P, getLocator());
2094+
return failure.diagnose(asNote);
2095+
}
2096+
2097+
IgnoreInvalidPatternInExpr *
2098+
IgnoreInvalidPatternInExpr::create(ConstraintSystem &cs, Pattern *pattern,
2099+
ConstraintLocator *locator) {
2100+
return new (cs.getAllocator())
2101+
IgnoreInvalidPatternInExpr(cs, pattern, locator);
2102+
}
2103+
20912104
bool SpecifyContextualTypeForNil::diagnose(const Solution &solution,
20922105
bool asNote) const {
20932106
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
@@ -14900,6 +14900,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1490014900
case FixKind::AddExplicitExistentialCoercion:
1490114901
case FixKind::DestructureTupleToMatchPackExpansionParameter:
1490214902
case FixKind::AllowValueExpansionWithoutPackReferences:
14903+
case FixKind::IgnoreInvalidPatternInExpr:
1490314904
case FixKind::IgnoreMissingEachKeyword:
1490414905
llvm_unreachable("handled elsewhere");
1490514906
}

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)