mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[CSOptimizer] Update unary call favoring to include resolved member references
Update special favoring logic for unlabeled unary calls to support non-overloads member references in argument positions. The original hack missed a case where a type of a member is known in advance (i.e. a property without overloads) because there as another hack (shrink) for that. This helps in situations like `Double(x)` where `x` is a property of some type that is referenced using an implicit `self.` injected by the compiler. Resolves: rdar://161419917
This commit is contained in:
@@ -14,10 +14,11 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TypeChecker.h"
|
||||
#include "OpenedExistentials.h"
|
||||
#include "TypeChecker.h"
|
||||
#include "swift/AST/ConformanceLookup.h"
|
||||
#include "swift/AST/ExistentialLayout.h"
|
||||
#include "swift/AST/Expr.h"
|
||||
#include "swift/AST/GenericSignature.h"
|
||||
#include "swift/Basic/Defer.h"
|
||||
#include "swift/Basic/OptionSet.h"
|
||||
@@ -28,7 +29,6 @@
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
@@ -709,15 +709,29 @@ static std::optional<DisjunctionInfo> preserveFavoringOfUnlabeledUnaryArgument(
|
||||
|
||||
auto *argument =
|
||||
argumentList->getUnlabeledUnaryExpr()->getSemanticsProvidingExpr();
|
||||
|
||||
// If the type associated with a member expression doesn't have any type
|
||||
// variables it means that it was resolved during pre-check to a single
|
||||
// declaration.
|
||||
//
|
||||
// This helps in situations like `Double(x)` where `x` is a property of some
|
||||
// type that is referenced using an implicit `self.` injected by the compiler.
|
||||
auto isResolvedMemberReference = [&cs](Expr *expr) -> bool {
|
||||
auto *UDE = dyn_cast<UnresolvedDotExpr>(expr);
|
||||
return UDE && !cs.getType(UDE)->hasTypeVariable();
|
||||
};
|
||||
|
||||
// The hack operated on "favored" types and only declaration references,
|
||||
// applications, and (dynamic) subscripts had them if they managed to
|
||||
// get an overload choice selected during constraint generation.
|
||||
// It's sometimes possible to infer a type of a literal and an operator
|
||||
// chain, so it should be allowed as well.
|
||||
//
|
||||
// It's sometimes possible to infer a type of a literal, an operator
|
||||
// chain, and a member, so it should be allowed as well.
|
||||
if (!(isExpr<DeclRefExpr>(argument) || isExpr<ApplyExpr>(argument) ||
|
||||
isExpr<SubscriptExpr>(argument) ||
|
||||
isExpr<DynamicSubscriptExpr>(argument) ||
|
||||
isExpr<LiteralExpr>(argument) || isExpr<BinaryExpr>(argument)))
|
||||
isExpr<LiteralExpr>(argument) || isExpr<BinaryExpr>(argument) ||
|
||||
isResolvedMemberReference(argument)))
|
||||
return DisjunctionInfo::none();
|
||||
|
||||
auto argumentType = cs.getType(argument)->getRValueType();
|
||||
|
||||
@@ -160,8 +160,8 @@ do {
|
||||
var p: UnsafeMutableRawPointer { get { fatalError() } }
|
||||
|
||||
func f(_ p: UnsafeMutableRawPointer) {
|
||||
// The old hack (which is now removed) couldn't handle member references, only direct declaration references.
|
||||
guard let x = UnsafeMutablePointer<Double>(OpaquePointer(self.p)) else {
|
||||
// expected-error@-1 {{initializer for conditional binding must have Optional type, not 'UnsafeMutablePointer<Double>'}}
|
||||
return
|
||||
}
|
||||
_ = x
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// RUN: %scale-test --begin 1 --end 16 --step 1 --select NumLeafScopes %s
|
||||
// REQUIRES: asserts,no_asan
|
||||
|
||||
// There was a performance hack that handled calls with a single unlabeled argument
|
||||
// in a very specific way. For source compatibility reasons old behavior has to be
|
||||
// preserved in the disjunction optimizer as well, but the old hack missed a case
|
||||
// where a type of a member is known in advance (i.e. a property without overloads)
|
||||
// because there as another hack (shrink) for that. This test makes sure that
|
||||
// performance for such cases won't regress in the future.
|
||||
|
||||
struct Test {
|
||||
var v = 0
|
||||
|
||||
func test() {
|
||||
let _ = 1.0 * (
|
||||
1.0 * Double(v) +
|
||||
%for i in range(1, N):
|
||||
%if i % 2 == 0:
|
||||
1.0 * Double(v) +
|
||||
%else:
|
||||
1.0 * Double(self.v) +
|
||||
%end
|
||||
%end
|
||||
1.0 * Double(v)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user