mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[reference-bindings] Put reference bindings support behind -enable-experimental-feature ReferenceBindings.
This commit is contained in:
@@ -964,6 +964,9 @@ ERROR(no_default_arg_closure,none,
|
||||
ERROR(no_default_arg_curried,none,
|
||||
"default arguments are not allowed in curried parameter lists", ())
|
||||
ERROR(var_pattern_in_var,none,
|
||||
"'%select{let||var}0' cannot appear nested inside another 'var' or "
|
||||
"'let' pattern", (unsigned))
|
||||
ERROR(var_pattern_in_var_inout,none,
|
||||
"'%select{let|inout|var}0' cannot appear nested inside another 'var', "
|
||||
"'let', or 'inout' pattern", (unsigned))
|
||||
ERROR(extra_var_in_multiple_pattern_list,none,
|
||||
|
||||
@@ -179,6 +179,9 @@ EXPERIMENTAL_FEATURE(ImportSymbolicCXXDecls, false)
|
||||
/// Generate bindings for functions that 'throw' in the C++ section of the generated Clang header.
|
||||
EXPERIMENTAL_FEATURE(GenerateBindingsForThrowingFunctionsInCXX, false)
|
||||
|
||||
/// Enable reference bindings.
|
||||
EXPERIMENTAL_FEATURE(ReferenceBindings, false)
|
||||
|
||||
#undef EXPERIMENTAL_FEATURE
|
||||
#undef UPCOMING_FEATURE
|
||||
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
|
||||
|
||||
@@ -2057,7 +2057,7 @@ DeclNameRef formDeclNameRef(ASTContext &ctx,
|
||||
bool isCxxClassTemplateSpec = false);
|
||||
|
||||
/// Whether a given token can be the start of a decl.
|
||||
bool isKeywordPossibleDeclStart(const Token &Tok);
|
||||
bool isKeywordPossibleDeclStart(const LangOptions &options, const Token &Tok);
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
|
||||
@@ -3220,6 +3220,11 @@ suppressingFeatureNoAsyncAvailability(PrintOptions &options,
|
||||
action();
|
||||
}
|
||||
|
||||
static bool usesFeatureReferenceBindings(Decl *decl) {
|
||||
auto *vd = dyn_cast<VarDecl>(decl);
|
||||
return vd && vd->getIntroducer() == VarDecl::Introducer::InOut;
|
||||
}
|
||||
|
||||
/// Suppress the printing of a particular feature.
|
||||
static void suppressingFeature(PrintOptions &options, Feature feature,
|
||||
llvm::function_ref<void()> action) {
|
||||
|
||||
@@ -4659,8 +4659,11 @@ static unsigned skipUntilMatchingRBrace(Parser &P,
|
||||
return OpenBraces;
|
||||
}
|
||||
|
||||
bool swift::isKeywordPossibleDeclStart(const Token &Tok) {
|
||||
bool swift::isKeywordPossibleDeclStart(const LangOptions &options,
|
||||
const Token &Tok) {
|
||||
switch (Tok.getKind()) {
|
||||
case tok::kw_inout:
|
||||
return options.hasFeature(Feature::ReferenceBindings);
|
||||
case tok::at_sign:
|
||||
case tok::kw_associatedtype:
|
||||
case tok::kw_case:
|
||||
@@ -4672,7 +4675,6 @@ bool swift::isKeywordPossibleDeclStart(const Token &Tok) {
|
||||
case tok::kw_func:
|
||||
case tok::kw_import:
|
||||
case tok::kw_init:
|
||||
case tok::kw_inout:
|
||||
case tok::kw_internal:
|
||||
case tok::kw_let:
|
||||
case tok::kw_operator:
|
||||
@@ -4749,7 +4751,7 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes) {
|
||||
// @rethrows does not follow the general rule of @<identifier> so
|
||||
// it is needed to short circuit this else there will be an infinite
|
||||
// loop on invalid attributes of just rethrows
|
||||
} else if (!isKeywordPossibleDeclStart(Tok)) {
|
||||
} else if (!isKeywordPossibleDeclStart(Context.LangOpts, Tok)) {
|
||||
// If this is obviously not the start of a decl, then we're done.
|
||||
return false;
|
||||
}
|
||||
@@ -4878,7 +4880,7 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes) {
|
||||
return true;
|
||||
|
||||
// If the next token is obviously not the start of a decl, bail early.
|
||||
if (!isKeywordPossibleDeclStart(Tok2))
|
||||
if (!isKeywordPossibleDeclStart(Context.LangOpts, Tok2))
|
||||
return false;
|
||||
|
||||
// Otherwise, do a recursive parse.
|
||||
@@ -5091,7 +5093,6 @@ Parser::parseDecl(ParseDeclOptions Flags,
|
||||
case tok::kw_extension:
|
||||
DeclResult = parseDeclExtension(Flags, Attributes);
|
||||
break;
|
||||
case tok::kw_inout:
|
||||
case tok::kw_let:
|
||||
case tok::kw_var: {
|
||||
parseBindingIntroducer(/*HasLetOrVarKeyword=*/true);
|
||||
@@ -5188,6 +5189,14 @@ Parser::parseDecl(ParseDeclOptions Flags,
|
||||
// Obvious nonsense.
|
||||
default:
|
||||
|
||||
// TODO: Once reference bindings is no longer experimental, move this into
|
||||
// kw_let, kw_var.
|
||||
if (Context.LangOpts.hasFeature(Feature::ReferenceBindings) &&
|
||||
Tok.getKind() == tok::kw_inout) {
|
||||
parseBindingIntroducer(/*HasLetOrVarKeyword=*/true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Tok.isContextualKeyword("actor") && peekToken().is(tok::identifier)) {
|
||||
Tok.setKind(tok::contextual_keyword);
|
||||
DeclResult = parseDeclClass(Flags, Attributes);
|
||||
|
||||
@@ -1105,15 +1105,25 @@ ParserResult<Pattern> Parser::parsePattern() {
|
||||
}
|
||||
return makeParserCodeCompletionStatus();
|
||||
case tok::kw_inout:
|
||||
// If we don't have the reference binding feature, break if we have
|
||||
// inout. Otherwise, go below.
|
||||
if (!Context.LangOpts.hasFeature(Feature::ReferenceBindings))
|
||||
break;
|
||||
LLVM_FALLTHROUGH;
|
||||
case tok::kw_var:
|
||||
case tok::kw_let: {
|
||||
auto newBindingState = PatternBindingState(Tok);
|
||||
SourceLoc varLoc = consumeToken();
|
||||
|
||||
// 'var', 'let', 'inout' patterns shouldn't nest.
|
||||
if (InBindingPattern.getIntroducer().hasValue())
|
||||
diagnose(varLoc, diag::var_pattern_in_var,
|
||||
*newBindingState.getSelectIndexForIntroducer());
|
||||
if (InBindingPattern.getIntroducer().hasValue()) {
|
||||
auto diag = diag::var_pattern_in_var;
|
||||
unsigned index = *newBindingState.getSelectIndexForIntroducer();
|
||||
if (Context.LangOpts.hasFeature(Feature::ReferenceBindings)) {
|
||||
diag = diag::var_pattern_in_var_inout;
|
||||
}
|
||||
diagnose(varLoc, diag, index);
|
||||
}
|
||||
|
||||
// 'let' isn't valid inside an implicitly immutable context, but var is.
|
||||
if (newBindingState.isLet() &&
|
||||
@@ -1142,18 +1152,21 @@ ParserResult<Pattern> Parser::parsePattern() {
|
||||
}
|
||||
|
||||
default:
|
||||
if (Tok.isKeyword() &&
|
||||
(peekToken().is(tok::colon) || peekToken().is(tok::equal))) {
|
||||
diagnose(Tok, diag::keyword_cant_be_identifier, Tok.getText());
|
||||
diagnose(Tok, diag::backticks_to_escape)
|
||||
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
|
||||
SourceLoc Loc = Tok.getLoc();
|
||||
consumeToken();
|
||||
return makeParserErrorResult(new (Context) AnyPattern(Loc));
|
||||
}
|
||||
diagnose(Tok, diag::expected_pattern);
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle the default case.
|
||||
if (Tok.isKeyword() &&
|
||||
(peekToken().is(tok::colon) || peekToken().is(tok::equal))) {
|
||||
diagnose(Tok, diag::keyword_cant_be_identifier, Tok.getText());
|
||||
diagnose(Tok, diag::backticks_to_escape)
|
||||
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
|
||||
SourceLoc Loc = Tok.getLoc();
|
||||
consumeToken();
|
||||
return makeParserErrorResult(new (Context) AnyPattern(Loc));
|
||||
}
|
||||
diagnose(Tok, diag::expected_pattern);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Pattern *Parser::createBindingFromPattern(SourceLoc loc, Identifier name,
|
||||
@@ -1329,9 +1342,13 @@ ParserResult<Pattern>
|
||||
Parser::parseMatchingPatternAsBinding(PatternBindingState newState,
|
||||
SourceLoc varLoc, bool isExprBasic) {
|
||||
// 'var', 'let', 'inout' patterns shouldn't nest.
|
||||
if (InBindingPattern.getIntroducer().hasValue())
|
||||
diagnose(varLoc, diag::var_pattern_in_var,
|
||||
if (InBindingPattern.getIntroducer().hasValue()) {
|
||||
auto diag = diag::var_pattern_in_var;
|
||||
if (Context.LangOpts.hasFeature(Feature::ReferenceBindings))
|
||||
diag = diag::var_pattern_in_var_inout;
|
||||
diagnose(varLoc, diag,
|
||||
*newState.getSelectIndexForIntroducer());
|
||||
}
|
||||
|
||||
// 'let' isn't valid inside an implicitly immutable context, but var is.
|
||||
if (newState.isLet() &&
|
||||
|
||||
@@ -32,16 +32,12 @@ case let a:
|
||||
a = 1 // expected-error {{cannot assign}}
|
||||
case inout a:
|
||||
a = 1
|
||||
case var var a: // expected-error {{'var' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
case var var a: // expected-error {{'var' cannot appear nested inside another 'var' or 'let' pattern}}
|
||||
a += 1
|
||||
case var let a: // expected-error {{'let' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
case var let a: // expected-error {{'let' cannot appear nested inside another 'var' or 'let' pattern}}
|
||||
print(a, terminator: "")
|
||||
case var (var b): // expected-error {{'var' cannot appear nested inside another 'var'}}
|
||||
b += 1
|
||||
case var inout a: // expected-error {{'inout' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
break
|
||||
case inout (inout b): // expected-error {{'inout' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
break
|
||||
// 'Any' pattern.
|
||||
case _:
|
||||
()
|
||||
|
||||
388
test/Parse/matching_patterns_reference_bindings.swift
Normal file
388
test/Parse/matching_patterns_reference_bindings.swift
Normal file
@@ -0,0 +1,388 @@
|
||||
// RUN: %target-typecheck-verify-swift -swift-version 4 -I %S/Inputs -enable-source-import -enable-experimental-feature ReferenceBindings
|
||||
|
||||
import imported_enums
|
||||
|
||||
// TODO: Implement tuple equality in the library.
|
||||
// BLOCKED: <rdar://problem/13822406>
|
||||
func ~= (x: (Int,Int,Int), y: (Int,Int,Int)) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var x:Int
|
||||
|
||||
func square(_ x: Int) -> Int { return x*x }
|
||||
|
||||
struct A<B> {
|
||||
struct C<D> { }
|
||||
}
|
||||
|
||||
switch x {
|
||||
// Expressions as patterns.
|
||||
case 0:
|
||||
()
|
||||
case 1 + 2:
|
||||
()
|
||||
case square(9):
|
||||
()
|
||||
|
||||
// 'var', 'let', and 'inout' patterns.
|
||||
case var a:
|
||||
a = 1
|
||||
case let a:
|
||||
a = 1 // expected-error {{cannot assign}}
|
||||
case inout a:
|
||||
a = 1
|
||||
case var var a: // expected-error {{'var' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
a += 1
|
||||
case var let a: // expected-error {{'let' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
print(a, terminator: "")
|
||||
case var (var b): // expected-error {{'var' cannot appear nested inside another 'var'}}
|
||||
b += 1
|
||||
case var inout a: // expected-error {{'inout' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
break
|
||||
case inout (inout b): // expected-error {{'inout' cannot appear nested inside another 'var', 'let', or 'inout' pattern}}
|
||||
break
|
||||
// 'Any' pattern.
|
||||
case _:
|
||||
()
|
||||
|
||||
// patterns are resolved in expression-only positions are errors.
|
||||
case 1 + (_): // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}}
|
||||
()
|
||||
}
|
||||
|
||||
switch (x,x) {
|
||||
case (var a, var a): // expected-error {{invalid redeclaration of 'a'}} expected-note {{'a' previously declared here}}
|
||||
fallthrough
|
||||
case _: // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
()
|
||||
}
|
||||
|
||||
switch (x,x) {
|
||||
case (inout a, inout a): // expected-error {{invalid redeclaration of 'a'}}
|
||||
// expected-note @-1 {{'a' previously declared here}}
|
||||
// xpected-warning @-2 {{variable 'a' was never used; consider replacing with '_' or removing it}}
|
||||
// xpected-warning @-3 {{variable 'a' was never used; consider replacing with '_' or removing it}}
|
||||
break
|
||||
}
|
||||
|
||||
var e : Any = 0
|
||||
|
||||
switch e { // expected-error {{switch must be exhaustive}} expected-note{{do you want to add a default clause?}}
|
||||
// 'is' pattern.
|
||||
case is Int,
|
||||
is A<Int>,
|
||||
is A<Int>.C<Int>,
|
||||
is (Int, Int),
|
||||
is (a: Int, b: Int):
|
||||
()
|
||||
}
|
||||
|
||||
// Enum patterns.
|
||||
enum Foo { case A, B, C }
|
||||
|
||||
func == <T>(_: Voluntary<T>, _: Voluntary<T>) -> Bool { return true }
|
||||
|
||||
enum Voluntary<T> : Equatable {
|
||||
case Naught
|
||||
case Mere(T)
|
||||
case Twain(T, T)
|
||||
|
||||
|
||||
func enumMethod(_ other: Voluntary<T>, foo: Foo) {
|
||||
switch self {
|
||||
case other:
|
||||
()
|
||||
|
||||
case .Naught,
|
||||
.Naught(), // expected-error {{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{17-19=}}
|
||||
.Naught(_), // expected-error{{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{17-20=}}
|
||||
.Naught(_, _): // expected-error{{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{17-23=}}
|
||||
()
|
||||
|
||||
case .Mere,
|
||||
.Mere(), // expected-error{{tuple pattern cannot match values of the non-tuple type 'T'}}
|
||||
.Mere(_),
|
||||
.Mere(_, _): // expected-error{{tuple pattern cannot match values of the non-tuple type 'T'}}
|
||||
()
|
||||
|
||||
case .Twain(), // expected-error{{tuple pattern has the wrong length for tuple type '(T, T)'}}
|
||||
.Twain(_), // expected-warning {{enum case 'Twain' has 2 associated values; matching them as a tuple is deprecated}}
|
||||
// expected-note@-25 {{'Twain' declared here}}
|
||||
.Twain(_, _),
|
||||
.Twain(_, _, _): // expected-error{{tuple pattern has the wrong length for tuple type '(T, T)'}}
|
||||
()
|
||||
}
|
||||
|
||||
switch foo {
|
||||
case .Naught: // expected-error{{type 'Foo' has no member 'Naught'}}
|
||||
()
|
||||
case .A, .B, .C:
|
||||
()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var n : Voluntary<Int> = .Naught
|
||||
if case let .Naught(value) = n {} // expected-error{{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{20-27=}}
|
||||
if case let .Naught(value1, value2, value3) = n {} // expected-error{{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{20-44=}}
|
||||
|
||||
if case inout .Naught(value) = n {} // expected-error{{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{22-29=}}
|
||||
if case inout .Naught(value1, value2, value3) = n {} // expected-error{{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{22-46=}}
|
||||
|
||||
|
||||
|
||||
switch n {
|
||||
case Foo.A: // expected-error{{enum case 'A' is not a member of type 'Voluntary<Int>'}}
|
||||
()
|
||||
case Voluntary<Int>.Naught,
|
||||
Voluntary<Int>.Naught(), // expected-error {{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{27-29=}}
|
||||
Voluntary<Int>.Naught(_, _), // expected-error{{pattern with associated values does not match enum case 'Naught'}}
|
||||
// expected-note@-1 {{remove associated values to make the pattern match}} {{27-33=}}
|
||||
Voluntary.Naught,
|
||||
.Naught:
|
||||
()
|
||||
case Voluntary<Int>.Mere,
|
||||
Voluntary<Int>.Mere(_),
|
||||
Voluntary<Int>.Mere(_, _), // expected-error{{tuple pattern cannot match values of the non-tuple type 'Int'}}
|
||||
Voluntary.Mere,
|
||||
Voluntary.Mere(_),
|
||||
.Mere,
|
||||
.Mere(_):
|
||||
()
|
||||
case .Twain,
|
||||
.Twain(_), // expected-warning {{enum case 'Twain' has 2 associated values; matching them as a tuple is deprecated}}
|
||||
// expected-note@-74 {{'Twain' declared here}}
|
||||
.Twain(_, _),
|
||||
.Twain(_, _, _): // expected-error{{tuple pattern has the wrong length for tuple type '(Int, Int)'}}
|
||||
()
|
||||
}
|
||||
|
||||
var notAnEnum = 0
|
||||
|
||||
switch notAnEnum {
|
||||
case .Foo: // expected-error{{type 'Int' has no member 'Foo'}}
|
||||
()
|
||||
}
|
||||
|
||||
struct ContainsEnum {
|
||||
enum Possible<T> {
|
||||
case Naught
|
||||
case Mere(T)
|
||||
case Twain(T, T)
|
||||
}
|
||||
|
||||
func member(_ n: Possible<Int>) {
|
||||
switch n { // expected-error {{switch must be exhaustive}}
|
||||
// expected-note@-1 {{missing case: '.Mere(_)'}}
|
||||
// expected-note@-2 {{missing case: '.Twain(_, _)'}}
|
||||
case ContainsEnum.Possible<Int>.Naught,
|
||||
ContainsEnum.Possible.Naught, // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
Possible<Int>.Naught, // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
Possible.Naught, // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
.Naught: // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func nonmemberAccessesMemberType(_ n: ContainsEnum.Possible<Int>) {
|
||||
switch n { // expected-error {{switch must be exhaustive}}
|
||||
// expected-note@-1 {{missing case: '.Mere(_)'}}
|
||||
// expected-note@-2 {{missing case: '.Twain(_, _)'}}
|
||||
case ContainsEnum.Possible<Int>.Naught,
|
||||
.Naught: // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
var m : ImportedEnum = .Simple
|
||||
|
||||
switch m {
|
||||
case imported_enums.ImportedEnum.Simple,
|
||||
ImportedEnum.Simple, // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
.Simple: // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
()
|
||||
case imported_enums.ImportedEnum.Compound,
|
||||
imported_enums.ImportedEnum.Compound(_), // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
ImportedEnum.Compound, // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
ImportedEnum.Compound(_), // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
.Compound, // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
.Compound(_): // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
()
|
||||
}
|
||||
|
||||
// Check that single-element tuple payloads work sensibly in patterns.
|
||||
|
||||
enum LabeledScalarPayload {
|
||||
case Payload(name: Int)
|
||||
}
|
||||
|
||||
var lsp: LabeledScalarPayload = .Payload(name: 0)
|
||||
func acceptInt(_: Int) {}
|
||||
func acceptString(_: String) {}
|
||||
|
||||
switch lsp {
|
||||
case .Payload(0):
|
||||
()
|
||||
case .Payload(name: 0):
|
||||
()
|
||||
case let .Payload(x):
|
||||
acceptInt(x)
|
||||
acceptString("\(x)")
|
||||
case let .Payload(name: x): // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
acceptInt(x)
|
||||
acceptString("\(x)")
|
||||
case let .Payload((name: x)): // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
acceptInt(x)
|
||||
acceptString("\(x)")
|
||||
case .Payload(let (name: x)): // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
acceptInt(x)
|
||||
acceptString("\(x)")
|
||||
case .Payload(let (name: x)): // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
acceptInt(x)
|
||||
acceptString("\(x)")
|
||||
case .Payload(let x): // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
acceptInt(x)
|
||||
acceptString("\(x)")
|
||||
case .Payload((let x)): // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
acceptInt(x)
|
||||
acceptString("\(x)")
|
||||
}
|
||||
|
||||
// Property patterns.
|
||||
|
||||
struct S {
|
||||
static var stat: Int = 0
|
||||
var x, y : Int
|
||||
var comp : Int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
func nonProperty() {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Tuple patterns.
|
||||
|
||||
var t = (1, 2, 3)
|
||||
|
||||
prefix operator +++
|
||||
infix operator +++
|
||||
prefix func +++(x: (Int,Int,Int)) -> (Int,Int,Int) { return x }
|
||||
func +++(x: (Int,Int,Int), y: (Int,Int,Int)) -> (Int,Int,Int) {
|
||||
return (x.0+y.0, x.1+y.1, x.2+y.2)
|
||||
}
|
||||
|
||||
switch t {
|
||||
case (_, var a, 3):
|
||||
a += 1
|
||||
case var (_, b, 3):
|
||||
b += 1
|
||||
case var (_, var c, 3): // expected-error{{'var' cannot appear nested inside another 'var'}}
|
||||
c += 1
|
||||
case (1, 2, 3):
|
||||
()
|
||||
|
||||
// patterns in expression-only positions are errors.
|
||||
case +++(_, var d, 3):
|
||||
// expected-error@-1{{'_' can only appear in a pattern or on the left side of an assignment}}
|
||||
()
|
||||
case (_, var e, 3) +++ (1, 2, 3):
|
||||
// expected-error@-1{{'_' can only appear in a pattern or on the left side of an assignment}}
|
||||
()
|
||||
case (let (_, _, _)) + 1:
|
||||
// expected-error@-1 {{'_' can only appear in a pattern or on the left side of an assignment}}
|
||||
()
|
||||
case (inout (_, _, 2)) + 1:
|
||||
// expected-error@-1 {{'_' can only appear in a pattern or on the left side of an assignment}}
|
||||
()
|
||||
}
|
||||
|
||||
// "isa" patterns.
|
||||
|
||||
// https://github.com/apple/swift/issues/56139
|
||||
// Allow subpatterns for "isa" patterns that require conditional
|
||||
// collection downcasts
|
||||
do {
|
||||
class Base { }
|
||||
class Derived : Base { }
|
||||
|
||||
let arr: [Base]
|
||||
|
||||
if case let _ as [Derived] = arr {}
|
||||
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}
|
||||
guard case let _ as [Derived] = arr else {}
|
||||
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}
|
||||
while case let _ as [Derived] = arr {}
|
||||
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}
|
||||
|
||||
// FIXME: https://github.com/apple/swift/issues/61850
|
||||
// expected-warning@+1 {{heterogeneous collection literal could only be inferred to '[[Base]]'; add explicit type annotation if this is intentional}}
|
||||
for case _ as [Derived] in [arr] {}
|
||||
|
||||
if case is [Derived] = arr {}
|
||||
|
||||
guard case is [Derived] = arr else {}
|
||||
|
||||
while case is [Derived] = arr {}
|
||||
|
||||
for case is [Derived] in [arr] {}
|
||||
|
||||
switch arr {
|
||||
case let ds as [Derived]:
|
||||
// expected-warning@-1 {{immutable value 'ds' was never used; consider replacing with '_' or removing it}}
|
||||
()
|
||||
case is [Derived]:
|
||||
()
|
||||
|
||||
default:
|
||||
()
|
||||
}
|
||||
|
||||
let _ = { (arr: [Base]) -> Void in
|
||||
switch arr {
|
||||
case let ds as [Derived]:
|
||||
// expected-warning@-1 {{immutable value 'ds' was never used; consider replacing with '_' or removing it}}
|
||||
()
|
||||
default:
|
||||
()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional patterns.
|
||||
let op1 : Int?
|
||||
let op2 : Int??
|
||||
|
||||
switch op1 {
|
||||
case nil: break
|
||||
case 1?: break
|
||||
case _?: break
|
||||
}
|
||||
|
||||
switch op2 {
|
||||
case nil: break
|
||||
case _?: break
|
||||
case (1?)?: break
|
||||
case (_?)?: break // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// <rdar://problem/20365753> Bogus diagnostic "refutable pattern match can fail"
|
||||
let (responseObject: Int?) = op1
|
||||
// expected-error @-1 {{expected ',' separator}} {{25-25=,}}
|
||||
// expected-error @-2 {{expected pattern}}
|
||||
// expected-error @-3 {{cannot convert value of type 'Int?' to specified type '(responseObject: _)'}}
|
||||
@@ -4,17 +4,14 @@ let _ = 1 // expected-error{{global variable declaration does not bind any varia
|
||||
|
||||
func foo() {
|
||||
let _ = 1 // OK
|
||||
inout _ = 1
|
||||
}
|
||||
|
||||
struct Foo {
|
||||
let _ = 1 // expected-error{{property declaration does not bind any variables}}
|
||||
var (_, _) = (1, 2) // expected-error{{property declaration does not bind any variables}}
|
||||
inout (_, _) = (1, 2) // expected-error{{property declaration does not bind any variables}}
|
||||
|
||||
func foo() {
|
||||
let _ = 1 // OK
|
||||
inout _ = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,13 +33,8 @@ func testVarLetPattern(a : SimpleEnum) {
|
||||
switch (a, 42) {
|
||||
case let (_, x): _ = x; break // ok
|
||||
}
|
||||
switch a {
|
||||
case inout _: break // expected-warning {{'inout' pattern has no effect; sub-pattern didn't bind any variables}} {{8-14=}}
|
||||
}
|
||||
// expected-warning @+1 {{'if' condition is always true}}
|
||||
if case let _ = "str" {} // expected-warning {{'let' pattern has no effect; sub-pattern didn't bind any variables}} {{11-15=}}
|
||||
if case inout _ = "str" {} // expected-warning {{'inout' pattern has no effect; sub-pattern didn't bind any variables}} {{11-17=}}
|
||||
// expected-warning @-1 {{'if' condition is always true}}
|
||||
}
|
||||
|
||||
// https://github.com/apple/swift/issues/53293
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// RUN: %target-typecheck-verify-swift -parse-as-library -enable-experimental-feature ReferenceBindings
|
||||
|
||||
// REQUIRES: asserts
|
||||
|
||||
let _ = 1 // expected-error{{global variable declaration does not bind any variables}}
|
||||
|
||||
func foo() {
|
||||
let _ = 1 // OK
|
||||
inout _ = 1
|
||||
}
|
||||
|
||||
struct Foo {
|
||||
let _ = 1 // expected-error{{property declaration does not bind any variables}}
|
||||
var (_, _) = (1, 2) // expected-error{{property declaration does not bind any variables}}
|
||||
inout (_, _) = (1, 2) // expected-error{{property declaration does not bind any variables}}
|
||||
|
||||
func foo() {
|
||||
let _ = 1 // OK
|
||||
inout _ = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// <rdar://problem/19786845> Warn on "let" and "var" when no data is bound in a pattern
|
||||
enum SimpleEnum { case Bar }
|
||||
|
||||
|
||||
func testVarLetPattern(a : SimpleEnum) {
|
||||
switch a {
|
||||
case let .Bar: break // expected-warning {{'let' pattern has no effect; sub-pattern didn't bind any variables}} {{8-12=}}
|
||||
}
|
||||
switch a {
|
||||
case let x: _ = x; break // Ok.
|
||||
}
|
||||
switch a {
|
||||
case let _: break // expected-warning {{'let' pattern has no effect; sub-pattern didn't bind any variables}} {{8-12=}}
|
||||
}
|
||||
switch (a, 42) {
|
||||
case let (_, x): _ = x; break // ok
|
||||
}
|
||||
switch a {
|
||||
case inout _: break // expected-warning {{'inout' pattern has no effect; sub-pattern didn't bind any variables}} {{8-14=}}
|
||||
}
|
||||
// expected-warning @+1 {{'if' condition is always true}}
|
||||
if case let _ = "str" {} // expected-warning {{'let' pattern has no effect; sub-pattern didn't bind any variables}} {{11-15=}}
|
||||
if case inout _ = "str" {} // expected-warning {{'inout' pattern has no effect; sub-pattern didn't bind any variables}} {{11-17=}}
|
||||
// expected-warning @-1 {{'if' condition is always true}}
|
||||
}
|
||||
|
||||
// https://github.com/apple/swift/issues/53293
|
||||
class C_53293 {
|
||||
static var _: Int { 0 } //expected-error {{getter/setter can only be defined for a single variable}}
|
||||
}
|
||||
Reference in New Issue
Block a user