[reference-bindings] Put reference bindings support behind -enable-experimental-feature ReferenceBindings.

This commit is contained in:
Michael Gottesman
2023-03-03 13:37:40 -08:00
parent fab3e3f84b
commit 78d57ea6be
10 changed files with 502 additions and 36 deletions

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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() &&

View File

@@ -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 _:
()

View 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: _)'}}

View File

@@ -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

View File

@@ -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}}
}