Skip to content

Commit a298302

Browse files
authored
Merge pull request #4516 from jtbandes/swift-3.0-branch
Swift 3: pull in fixes from master branch
2 parents 826ff03 + 2c998bd commit a298302

File tree

6 files changed

+108
-73
lines changed

6 files changed

+108
-73
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,9 @@ ERROR(parameter_unnamed,none,
746746
ERROR(parameter_curry_syntax_removed,none,
747747
"curried function declaration syntax has been removed; use a single parameter list", ())
748748

749+
ERROR(initializer_as_typed_pattern,none,
750+
"unexpected initializer in pattern; did you mean to use '='?", ())
751+
749752
//------------------------------------------------------------------------------
750753
// Statement parsing diagnostics
751754
//------------------------------------------------------------------------------

lib/Parse/ParsePattern.cpp

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,15 +788,63 @@ ParserResult<Pattern> Parser::parseTypedPattern() {
788788
auto result = parsePattern();
789789

790790
// Now parse an optional type annotation.
791-
if (consumeIf(tok::colon)) {
791+
if (Tok.is(tok::colon)) {
792+
SourceLoc pastEndOfPrevLoc = getEndOfPreviousLoc();
793+
SourceLoc colonLoc = consumeToken(tok::colon);
794+
SourceLoc startOfNextLoc = Tok.getLoc();
795+
792796
if (result.isNull()) // Recover by creating AnyPattern.
793797
result = makeParserErrorResult(new (Context) AnyPattern(PreviousLoc));
794798

795799
ParserResult<TypeRepr> Ty = parseType();
796800
if (Ty.hasCodeCompletion())
797801
return makeParserCodeCompletionResult<Pattern>();
798-
if (Ty.isNull())
802+
if (!Ty.isNull()) {
803+
// Attempt to diagnose initializer calls incorrectly written
804+
// as typed patterns, such as "var x: [Int]()".
805+
if (Tok.isFollowingLParen()) {
806+
BacktrackingScope backtrack(*this);
807+
808+
// Create a local context if needed so we can parse trailing closures.
809+
LocalContext dummyContext;
810+
Optional<ContextChange> contextChange;
811+
if (!CurLocalContext) {
812+
contextChange.emplace(*this, CurDeclContext, &dummyContext);
813+
}
814+
815+
SourceLoc lParenLoc, rParenLoc;
816+
SmallVector<Expr *, 2> args;
817+
SmallVector<Identifier, 2> argLabels;
818+
SmallVector<SourceLoc, 2> argLabelLocs;
819+
Expr *trailingClosure;
820+
ParserStatus status = parseExprList(tok::l_paren, tok::r_paren,
821+
/*isPostfix=*/true,
822+
/*isExprBasic=*/false,
823+
lParenLoc, args, argLabels,
824+
argLabelLocs, rParenLoc,
825+
trailingClosure);
826+
if (status.isSuccess()) {
827+
backtrack.cancelBacktrack();
828+
829+
// Suggest replacing ':' with '=' (ensuring proper whitespace).
830+
831+
bool needSpaceBefore = (pastEndOfPrevLoc == colonLoc);
832+
bool needSpaceAfter =
833+
SourceMgr.getByteDistance(colonLoc, startOfNextLoc) <= 1;
834+
835+
StringRef replacement = " = ";
836+
if (!needSpaceBefore) replacement = replacement.drop_front();
837+
if (!needSpaceAfter) replacement = replacement.drop_back();
838+
839+
diagnose(lParenLoc, diag::initializer_as_typed_pattern)
840+
.highlight({Ty.get()->getStartLoc(), rParenLoc})
841+
.fixItReplace(colonLoc, replacement);
842+
result.setIsParseError();
843+
}
844+
}
845+
} else {
799846
Ty = makeParserResult(new (Context) ErrorTypeRepr(PreviousLoc));
847+
}
800848

801849
result = makeParserResult(result,
802850
new (Context) TypedPattern(result.get(), Ty.get()));

lib/Sema/TypeCheckPattern.cpp

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,8 +1459,10 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
14591459

14601460
case PatternKind::OptionalSome: {
14611461
auto *OP = cast<OptionalSomePattern>(P);
1462-
auto *enumDecl = type->getEnumOrBoundGenericEnum();
1463-
if (!enumDecl) {
1462+
OptionalTypeKind optionalKind;
1463+
Type elementType = type->getAnyOptionalObjectType(optionalKind);
1464+
1465+
if (elementType.isNull()) {
14641466
auto diagID = diag::optional_element_pattern_not_valid_type;
14651467
SourceLoc loc = OP->getQuestionLoc();
14661468
// Produce tailored diagnostic for if/let and other conditions.
@@ -1473,35 +1475,10 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
14731475
return true;
14741476
}
14751477

1476-
// If the element decl was not resolved (because it was spelled without a
1477-
// type as `.Foo`), resolve it now that we have a type.
1478-
if (!OP->getElementDecl()) {
1479-
auto *element = lookupEnumMemberElement(*this, dc, type, Context.Id_some,
1480-
OP->getLoc());
1481-
if (!element) {
1482-
diagnose(OP->getLoc(), diag::enum_element_pattern_member_not_found,
1483-
"Some", type);
1484-
return true;
1485-
}
1486-
OP->setElementDecl(element);
1487-
}
1488-
1489-
EnumElementDecl *elt = OP->getElementDecl();
1490-
// Is the enum element actually part of the enum type we're matching?
1491-
if (elt->getParentEnum() != enumDecl) {
1492-
diagnose(OP->getLoc(), diag::enum_element_pattern_not_member_of_enum,
1493-
"Some", type);
1494-
return true;
1495-
}
1478+
EnumElementDecl *elementDecl = Context.getOptionalSomeDecl(optionalKind);
1479+
assert(elementDecl && "missing optional some decl?!");
1480+
OP->setElementDecl(elementDecl);
14961481

1497-
// Check the subpattern & push the enum element type down onto it.
1498-
Type elementType;
1499-
if (elt->hasArgumentType())
1500-
elementType = type->getTypeOfMember(elt->getModuleContext(),
1501-
elt, this,
1502-
elt->getArgumentInterfaceType());
1503-
else
1504-
elementType = TupleType::getEmpty(Context);
15051482
Pattern *sub = OP->getSubPattern();
15061483
if (coercePatternToType(sub, dc, elementType,
15071484
subOptions|TR_FromNonInferredPattern|TR_EnumPatternPayload,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-parse-verify-swift
2+
3+
// https://bugs.swift.org/browse/SR-1461
4+
5+
class X {}
6+
func foo() {}
7+
8+
let a:[X]() // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= = }}
9+
let b: [X]() // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= =}}
10+
let c :[X]() // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{7-8== }}
11+
let d : [X]() // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{7-8==}}
12+
13+
let e: X(), ee: Int // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= =}}
14+
15+
var _1 = 1, _2 = 2
16+
17+
// paren follows the type, but it's part of a separate (valid) expression
18+
let ff: X
19+
(_1, _2) = (_2, _1)
20+
let fff: X
21+
(_1, _2) = (_2, _1)
22+
23+
let g: X(x) // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= =}}
24+
let h: X(x, y) // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= =}}
25+
let i: X() { foo() } // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= =}}
26+
let j: X(x) { foo() } // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= =}}
27+
let k: X(x, y) { foo() } // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{6-7= =}}
28+
29+
func nonTopLevel() {
30+
let a:[X]() // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{8-9= = }}
31+
let i: X() { foo() } // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{8-9= =}}
32+
let j: X(x) { foo() } // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{8-9= =}}
33+
let k: X(x, y) { foo() } // expected-error{{unexpected initializer in pattern; did you mean to use '='?}} {{8-9= =}}
34+
_ = (a, i, j, k)
35+
}

test/SILGen/statements.swift

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -591,45 +591,6 @@ func testRequireOptional2(_ a : String?) -> String {
591591
return t
592592
}
593593

594-
enum MyOptional<Wrapped> {
595-
case none
596-
case some(Wrapped)
597-
}
598-
599-
// CHECK-LABEL: sil hidden @_TF10statements28testAddressOnlyEnumInRequire
600-
// CHECK: bb0(%0 : $*T, %1 : $*MyOptional<T>):
601-
// CHECK-NEXT: debug_value_addr %1 : $*MyOptional<T>, let, name "a"
602-
// CHECK-NEXT: %3 = alloc_stack $T, let, name "t"
603-
// CHECK-NEXT: %4 = alloc_stack $MyOptional<T>
604-
// CHECK-NEXT: copy_addr %1 to [initialization] %4 : $*MyOptional<T>
605-
// CHECK-NEXT: switch_enum_addr %4 : $*MyOptional<T>, case #MyOptional.some!enumelt.1: bb2, default bb1
606-
func testAddressOnlyEnumInRequire<T>(_ a: MyOptional<T>) -> T {
607-
// CHECK: bb1:
608-
// CHECK-NEXT: dealloc_stack %4
609-
// CHECK-NEXT: dealloc_stack %3
610-
// CHECK-NEXT: br bb3
611-
guard let t = a else { abort() }
612-
613-
// CHECK: bb2:
614-
// CHECK-NEXT: %10 = unchecked_take_enum_data_addr %4 : $*MyOptional<T>, #MyOptional.some!enumelt.1
615-
// CHECK-NEXT: copy_addr [take] %10 to [initialization] %3 : $*T
616-
// CHECK-NEXT: dealloc_stack %4
617-
// CHECK-NEXT: copy_addr [take] %3 to [initialization] %0 : $*T
618-
// CHECK-NEXT: dealloc_stack %3
619-
// CHECK-NEXT: destroy_addr %1 : $*MyOptional<T>
620-
// CHECK-NEXT: tuple ()
621-
// CHECK-NEXT: return
622-
623-
// CHECK: bb3:
624-
// CHECK-NEXT: // function_ref statements.abort () -> Swift.Never
625-
// CHECK-NEXT: %18 = function_ref @_TF10statements5abortFT_Os5Never
626-
// CHECK-NEXT: %19 = apply %18() : $@convention(thin) () -> Never
627-
// CHECK-NEXT: unreachable
628-
629-
return t
630-
}
631-
632-
633594

634595
// CHECK-LABEL: sil hidden @_TF10statements19testCleanupEmission
635596
// <rdar://problem/20563234> let-else problem: cleanups for bound patterns shouldn't be run in the else block

test/stmt/if_while_var.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
// RUN: %target-parse-verify-swift
22

3+
struct NonOptionalStruct {}
4+
enum NonOptionalEnum { case foo }
5+
36
func foo() -> Int? { return .none }
4-
func nonOptional() -> Int { return 0 }
7+
func nonOptionalStruct() -> NonOptionalStruct { fatalError() }
8+
func nonOptionalEnum() -> NonOptionalEnum { fatalError() }
59
func use(_ x: Int) {}
610
func modify(_ x: inout Int) {}
711

@@ -19,7 +23,14 @@ if var x = foo() {
1923

2024
use(x) // expected-error{{unresolved identifier 'x'}}
2125

22-
if let x = nonOptional() { } // expected-error{{initializer for conditional binding must have Optional type, not 'Int'}}
26+
if let x = nonOptionalStruct() { } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalStruct'}}
27+
if let x = nonOptionalEnum() { } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalEnum'}}
28+
29+
guard let _ = nonOptionalStruct() else { fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalStruct'}}
30+
guard let _ = nonOptionalEnum() else { fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalEnum'}}
31+
32+
if case let x? = nonOptionalStruct() { } // expected-error{{'?' pattern cannot match values of type 'NonOptionalStruct'}}
33+
if case let x? = nonOptionalEnum() { } // expected-error{{'?' pattern cannot match values of type 'NonOptionalEnum'}}
2334

2435
class B {} // expected-note * {{did you mean 'B'?}}
2536
class D : B {}// expected-note * {{did you mean 'D'?}}

0 commit comments

Comments
 (0)