From c62e219ba246f33067a5fe1e41c87a4553b3e7fc Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Fri, 5 Nov 2021 21:12:59 -0700 Subject: [PATCH] [CSGen] Don't walk into ?? in LinkedExprAnalyzer. Attempting to favor the type of this expression based on operand types is wrong, because this operator attempts to unwrap its operand types. --- include/swift/AST/Identifier.h | 4 ++++ lib/Sema/CSGen.cpp | 12 ++++++++++-- test/Constraints/nil-coalescing-favoring.swift | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 test/Constraints/nil-coalescing-favoring.swift diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index f3999438ed0a5..6f65385e0973e 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -122,6 +122,10 @@ class Identifier { is(">") || is("<=") || is(">="); } + bool isNilCoalescingOperator() const { + return is("??"); + } + /// isOperatorStartCodePoint - Return true if the specified code point is a /// valid start of an operator. static bool isOperatorStartCodePoint(uint32_t C) { diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 106b2b346ecb9..241c9a81580a1 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -212,7 +212,15 @@ namespace { return { false, expr }; } - if (isa(expr)) { + if (auto *binaryExpr = dyn_cast(expr)) { + if (auto *overload = dyn_cast(binaryExpr->getFn())) { + // Don't walk into nil coalescing operators. Attempting to favor + // based on operand types is wrong for this operator. + auto identifier = overload->getDecls().front()->getBaseIdentifier(); + if (identifier.isNilCoalescingOperator()) + return { false, expr }; + } + LTI.binaryExprs.push_back(dyn_cast(expr)); } @@ -367,7 +375,7 @@ namespace { return true; } - + return false; } diff --git a/test/Constraints/nil-coalescing-favoring.swift b/test/Constraints/nil-coalescing-favoring.swift new file mode 100644 index 0000000000000..0001f97014b4a --- /dev/null +++ b/test/Constraints/nil-coalescing-favoring.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-frontend -dump-ast %s | %FileCheck %s + +struct B { + static var _none: B { B() } +} + +struct A { + init(_ other: B) {} + // CHECK: constructor_decl{{.*}}interface type='(A.Type) -> (B?) -> A' + init(_ other: B?) { + // CHECK: dot_syntax_call_expr type='(B) -> A' + self.init(other ?? ._none) + } +}