Skip to content

Commit 73fb36f

Browse files
committed
[AST] Split out "is compound" bit on FunctionRefInfo
FunctionRefKind was originally designed to represent the handling needed for argument labels on function references, in which the unapplied and compound cases are effectively the same. However it has since been adopted in a bunch of other places where the spelling of the function reference is entirely orthogonal to the application level. Split out the application level from the "is compound" bit. Should be NFC. I've left some FIXMEs for non-NFC changes that I'll address in a follow-up.
1 parent a4d5141 commit 73fb36f

25 files changed

+393
-249
lines changed

include/swift/AST/Expr.h

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -193,16 +193,16 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
193193
LiteralCapacity : 32
194194
);
195195

196-
SWIFT_INLINE_BITFIELD(DeclRefExpr, Expr, 2+2+1+1,
196+
SWIFT_INLINE_BITFIELD(DeclRefExpr, Expr, 2+3+1+1,
197197
Semantics : 2, // an AccessSemantics
198-
FunctionRefInfo : 2,
198+
FunctionRefInfo : 3,
199199
IsImplicitlyAsync : 1,
200200
IsImplicitlyThrows : 1
201201
);
202202

203-
SWIFT_INLINE_BITFIELD(UnresolvedDeclRefExpr, Expr, 2+2,
203+
SWIFT_INLINE_BITFIELD(UnresolvedDeclRefExpr, Expr, 2+3,
204204
DeclRefKind : 2,
205-
FunctionRefInfo : 2
205+
FunctionRefInfo : 3
206206
);
207207

208208
SWIFT_INLINE_BITFIELD(MemberRefExpr, LookupExpr, 2,
@@ -225,8 +225,8 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
225225
NumElements : 32
226226
);
227227

228-
SWIFT_INLINE_BITFIELD(UnresolvedDotExpr, Expr, 2,
229-
FunctionRefInfo : 2
228+
SWIFT_INLINE_BITFIELD(UnresolvedDotExpr, Expr, 3,
229+
FunctionRefInfo : 3
230230
);
231231

232232
SWIFT_INLINE_BITFIELD_FULL(SubscriptExpr, LookupExpr, 2,
@@ -235,12 +235,12 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
235235

236236
SWIFT_INLINE_BITFIELD_EMPTY(DynamicSubscriptExpr, DynamicLookupExpr);
237237

238-
SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 2,
239-
FunctionRefInfo : 2
238+
SWIFT_INLINE_BITFIELD_FULL(UnresolvedMemberExpr, Expr, 3,
239+
FunctionRefInfo : 3
240240
);
241241

242-
SWIFT_INLINE_BITFIELD(OverloadSetRefExpr, Expr, 2,
243-
FunctionRefInfo : 2
242+
SWIFT_INLINE_BITFIELD(OverloadSetRefExpr, Expr, 3,
243+
FunctionRefInfo : 3
244244
);
245245

246246
SWIFT_INLINE_BITFIELD(BooleanLiteralExpr, LiteralExpr, 1,
@@ -1230,12 +1230,10 @@ class DeclRefExpr : public Expr {
12301230
Type Ty = Type())
12311231
: Expr(ExprKind::DeclRef, Implicit, Ty), D(D), Loc(Loc),
12321232
implicitActorHopTarget(ActorIsolation::forUnspecified()) {
1233-
Bits.DeclRefExpr.Semantics = (unsigned) semantics;
1234-
Bits.DeclRefExpr.FunctionRefInfo =
1235-
static_cast<unsigned>(Loc.isCompound() ? FunctionRefInfo::Compound
1236-
: FunctionRefInfo::Unapplied);
1233+
Bits.DeclRefExpr.Semantics = (unsigned)semantics;
12371234
Bits.DeclRefExpr.IsImplicitlyAsync = false;
12381235
Bits.DeclRefExpr.IsImplicitlyThrows = false;
1236+
setFunctionRefInfo(FunctionRefInfo::unapplied(Loc));
12391237
}
12401238

12411239
/// Retrieve the declaration to which this expression refers.
@@ -1301,12 +1299,13 @@ class DeclRefExpr : public Expr {
13011299

13021300
/// Retrieve the kind of function reference.
13031301
FunctionRefInfo getFunctionRefInfo() const {
1304-
return static_cast<FunctionRefInfo>(Bits.DeclRefExpr.FunctionRefInfo);
1302+
return FunctionRefInfo::fromOpaque(Bits.DeclRefExpr.FunctionRefInfo);
13051303
}
13061304

13071305
/// Set the kind of function reference.
13081306
void setFunctionRefInfo(FunctionRefInfo refKind) {
1309-
Bits.DeclRefExpr.FunctionRefInfo = static_cast<unsigned>(refKind);
1307+
Bits.DeclRefExpr.FunctionRefInfo = refKind.getOpaqueValue();
1308+
ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
13101309
}
13111310

13121311
static bool classof(const Expr *E) {
@@ -1508,8 +1507,7 @@ class OverloadSetRefExpr : public Expr {
15081507
OverloadSetRefExpr(ExprKind Kind, ArrayRef<ValueDecl*> decls,
15091508
FunctionRefInfo functionRefInfo, bool Implicit, Type Ty)
15101509
: Expr(Kind, Implicit, Ty), Decls(decls) {
1511-
Bits.OverloadSetRefExpr.FunctionRefInfo =
1512-
static_cast<unsigned>(functionRefInfo);
1510+
setFunctionRefInfo(functionRefInfo);
15131511
}
15141512

15151513
public:
@@ -1530,13 +1528,13 @@ class OverloadSetRefExpr : public Expr {
15301528

15311529
/// Retrieve the kind of function reference.
15321530
FunctionRefInfo getFunctionRefInfo() const {
1533-
return static_cast<FunctionRefInfo>(
1534-
Bits.OverloadSetRefExpr.FunctionRefInfo);
1531+
return FunctionRefInfo::fromOpaque(Bits.OverloadSetRefExpr.FunctionRefInfo);
15351532
}
15361533

15371534
/// Set the kind of function reference.
15381535
void setFunctionRefInfo(FunctionRefInfo refKind) {
1539-
Bits.OverloadSetRefExpr.FunctionRefInfo = static_cast<unsigned>(refKind);
1536+
Bits.OverloadSetRefExpr.FunctionRefInfo = refKind.getOpaqueValue();
1537+
ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
15401538
}
15411539

15421540
static bool classof(const Expr *E) {
@@ -1584,9 +1582,7 @@ class UnresolvedDeclRefExpr : public Expr {
15841582
: Expr(ExprKind::UnresolvedDeclRef, /*Implicit=*/loc.isInvalid()),
15851583
Name(name), Loc(loc) {
15861584
Bits.UnresolvedDeclRefExpr.DeclRefKind = static_cast<unsigned>(refKind);
1587-
Bits.UnresolvedDeclRefExpr.FunctionRefInfo =
1588-
static_cast<unsigned>(Loc.isCompound() ? FunctionRefInfo::Compound
1589-
: FunctionRefInfo::Unapplied);
1585+
setFunctionRefInfo(FunctionRefInfo::unapplied(loc));
15901586
}
15911587

15921588
static UnresolvedDeclRefExpr *createImplicit(
@@ -1617,13 +1613,14 @@ class UnresolvedDeclRefExpr : public Expr {
16171613

16181614
/// Retrieve the kind of function reference.
16191615
FunctionRefInfo getFunctionRefInfo() const {
1620-
return static_cast<FunctionRefInfo>(
1621-
Bits.UnresolvedDeclRefExpr.FunctionRefInfo);
1616+
return FunctionRefInfo::fromOpaque(
1617+
Bits.UnresolvedDeclRefExpr.FunctionRefInfo);
16221618
}
16231619

16241620
/// Set the kind of function reference.
16251621
void setFunctionRefInfo(FunctionRefInfo refKind) {
1626-
Bits.UnresolvedDeclRefExpr.FunctionRefInfo = static_cast<unsigned>(refKind);
1622+
Bits.UnresolvedDeclRefExpr.FunctionRefInfo = refKind.getOpaqueValue();
1623+
ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
16271624
}
16281625

16291626
DeclNameLoc getNameLoc() const { return Loc; }
@@ -1901,19 +1898,18 @@ class UnresolvedMemberExpr final
19011898
bool implicit)
19021899
: Expr(ExprKind::UnresolvedMember, implicit), DotLoc(dotLoc),
19031900
NameLoc(nameLoc), Name(name) {
1904-
// FIXME: Really, we should be setting this to `FunctionRefInfo::Compound`
1905-
// if `NameLoc` is compound, but this would be a source break for cases like
1901+
// FIXME(FunctionRefInfo): Really, we should be passing `nameLoc` directly,
1902+
// allowing the FunctionRefInfo to be treated as compound. This would
1903+
// require us to enable IUOs for compound names, e.g:
19061904
// ```
19071905
// struct S {
19081906
// static func makeS(_: Int) -> S! { S() }
19091907
// }
19101908
//
19111909
// let s: S = .makeS(_:)(0)
19121910
// ```
1913-
// Instead, we should store compound-ness as a separate bit from applied/
1914-
// unapplied.
1915-
Bits.UnresolvedMemberExpr.FunctionRefInfo =
1916-
static_cast<unsigned>(FunctionRefInfo::Unapplied);
1911+
setFunctionRefInfo(
1912+
FunctionRefInfo::unapplied(DeclNameLoc(nameLoc.getBaseNameLoc())));
19171913
}
19181914

19191915
DeclNameRef getName() const { return Name; }
@@ -1927,15 +1923,16 @@ class UnresolvedMemberExpr final
19271923

19281924
/// Retrieve the kind of function reference.
19291925
FunctionRefInfo getFunctionRefInfo() const {
1930-
return static_cast<FunctionRefInfo>(
1926+
return FunctionRefInfo::fromOpaque(
19311927
Bits.UnresolvedMemberExpr.FunctionRefInfo);
19321928
}
19331929

19341930
/// Set the kind of function reference.
19351931
void setFunctionRefInfo(FunctionRefInfo refKind) {
1936-
Bits.UnresolvedMemberExpr.FunctionRefInfo = static_cast<unsigned>(refKind);
1932+
Bits.UnresolvedMemberExpr.FunctionRefInfo = refKind.getOpaqueValue();
1933+
ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
19371934
}
1938-
1935+
19391936
static bool classof(const Expr *E) {
19401937
return E->getKind() == ExprKind::UnresolvedMember;
19411938
}
@@ -2627,9 +2624,7 @@ class UnresolvedDotExpr : public Expr {
26272624
: Expr(ExprKind::UnresolvedDot, Implicit), SubExpr(subexpr),
26282625
DotLoc(dotloc), NameLoc(nameloc), Name(name),
26292626
OuterAlternatives(outerAlternatives) {
2630-
Bits.UnresolvedDotExpr.FunctionRefInfo =
2631-
static_cast<unsigned>(NameLoc.isCompound() ? FunctionRefInfo::Compound
2632-
: FunctionRefInfo::Unapplied);
2627+
setFunctionRefInfo(FunctionRefInfo::unapplied(nameloc));
26332628
}
26342629

26352630
static UnresolvedDotExpr *createImplicit(
@@ -2693,12 +2688,13 @@ class UnresolvedDotExpr : public Expr {
26932688

26942689
/// Retrieve the kind of function reference.
26952690
FunctionRefInfo getFunctionRefInfo() const {
2696-
return static_cast<FunctionRefInfo>(Bits.UnresolvedDotExpr.FunctionRefInfo);
2691+
return FunctionRefInfo::fromOpaque(Bits.UnresolvedDotExpr.FunctionRefInfo);
26972692
}
26982693

26992694
/// Set the kind of function reference.
27002695
void setFunctionRefInfo(FunctionRefInfo refKind) {
2701-
Bits.UnresolvedDotExpr.FunctionRefInfo = static_cast<unsigned>(refKind);
2696+
Bits.UnresolvedDotExpr.FunctionRefInfo = refKind.getOpaqueValue();
2697+
ASSERT(refKind == getFunctionRefInfo() && "FunctionRefInfo truncated");
27022698
}
27032699

27042700
static bool classof(const Expr *E) {

include/swift/AST/FunctionRefInfo.h

Lines changed: 129 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,158 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
1212
//
13-
// This file defines the FunctionRefInfo enum, which is used to describe how
13+
// This file defines the FunctionRefInfo class, which describes how a function
14+
// is referenced in an expression.
1415
//
1516
//===----------------------------------------------------------------------===//
1617

1718
#ifndef SWIFT_AST_FUNCTION_REF_INFO_H
1819
#define SWIFT_AST_FUNCTION_REF_INFO_H
1920

20-
#include "llvm/ADT/StringRef.h"
21+
#include "swift/Basic/Debug.h"
22+
#include "swift/Basic/LLVM.h"
2123

2224
namespace swift {
2325

24-
/// Describes how a function is referenced within an expression node,
25-
/// which dictates whether argument labels are part of the resulting
26-
/// function type or not.
26+
class DeclNameLoc;
27+
class DeclNameRef;
28+
29+
/// Describes how a function is referenced within an expression node.
30+
///
31+
/// This dictates things like:
32+
/// - Whether argument labels are part of the resulting function type or not.
33+
/// - Whether the result can produce an implicitly unwrapped optional.
34+
/// - Whether the function type needs adjustment for concurrency.
2735
///
2836
/// How a function is referenced comes down to how it was spelled in
2937
/// the source code, e.g., was it called in the source code and was it
3038
/// spelled as a compound name.
31-
enum class FunctionRefInfo : unsigned {
32-
/// The function was referenced using a bare function name (e.g.,
33-
/// 'f') and not directly called.
34-
Unapplied,
35-
/// The function was referenced using a bare function name and was
36-
/// directly applied once, e.g., "f(a: 1, b: 2)".
37-
SingleApply,
38-
/// The function was referenced using a bare function name and was
39-
/// directly applied two or more times, e.g., "g(x)(y)".
40-
DoubleApply,
41-
/// The function was referenced using a compound function name,
39+
class FunctionRefInfo final {
40+
public:
41+
/// Whether the function reference is part of a call, and if so how many
42+
/// applications were used.
43+
enum class ApplyLevel : uint8_t {
44+
/// The function is not directly called.
45+
Unapplied,
46+
/// The function is directly applied once, e.g., "f(a: 1, b: 2)".
47+
SingleApply,
48+
/// The function is directly applied two or more times, e.g., "g(x)(y)".
49+
DoubleApply,
50+
};
51+
52+
private:
53+
/// The application level of the function reference.
54+
ApplyLevel ApplyLevelKind;
55+
56+
/// Whether the function was referenced using a compound function name,
4257
/// e.g., "f(a:b:)".
43-
Compound,
44-
};
58+
bool IsCompoundName;
59+
60+
FunctionRefInfo(ApplyLevel applyLevel, bool isCompoundName)
61+
: ApplyLevelKind(applyLevel), IsCompoundName(isCompoundName) {}
62+
63+
public:
64+
/// An unapplied function reference for a given DeclNameLoc.
65+
static FunctionRefInfo unapplied(DeclNameLoc nameLoc);
66+
67+
/// An unapplied function reference for a given DeclNameRef.
68+
static FunctionRefInfo unapplied(DeclNameRef nameRef);
69+
70+
/// An unapplied function reference using a base name, e.g `let x = fn`.
71+
static FunctionRefInfo unappliedBaseName() {
72+
return FunctionRefInfo(ApplyLevel::Unapplied, /*isCompoundName*/ false);
73+
}
74+
75+
/// An unapplied function reference using a compound name,
76+
/// e.g `let x = fn(x:)`.
77+
static FunctionRefInfo unappliedCompoundName() {
78+
return FunctionRefInfo(ApplyLevel::Unapplied, /*isCompoundName*/ true);
79+
}
80+
81+
/// A single application using a base name, e.g `fn(x: 0)`.
82+
static FunctionRefInfo singleBaseNameApply() {
83+
return FunctionRefInfo(ApplyLevel::SingleApply, /*isCompoundName*/ false);
84+
}
85+
86+
/// A single application using a compound name, e.g `fn(x:)(0)`.
87+
static FunctionRefInfo singleCompoundNameApply() {
88+
return FunctionRefInfo(ApplyLevel::SingleApply, /*isCompoundName*/ true);
89+
}
4590

46-
/// Produce a string describing a function reference kind, for
47-
/// debugging purposes.
48-
llvm::StringRef getFunctionRefInfoStr(FunctionRefInfo refKind);
91+
/// A double application using a base name, e.g `S.fn(S())(x: 0)`.
92+
static FunctionRefInfo doubleBaseNameApply() {
93+
return FunctionRefInfo(ApplyLevel::DoubleApply, /*isCompoundName*/ false);
94+
}
4995

96+
/// A double application using a compound name, e.g `S.fn(x:)(S())(0)`.
97+
static FunctionRefInfo doubleCompoundNameApply() {
98+
return FunctionRefInfo(ApplyLevel::DoubleApply, /*isCompoundName*/ true);
99+
}
100+
101+
/// Reconstructs a FunctionRefInfo from its \c getOpaqueValue().
102+
static FunctionRefInfo fromOpaque(uint8_t bits) {
103+
return FunctionRefInfo(static_cast<ApplyLevel>(bits >> 1), bits & 0x1);
104+
}
105+
106+
/// Retrieves an opaque value that can be stored in e.g a bitfield.
107+
uint8_t getOpaqueValue() const {
108+
return (static_cast<uint8_t>(ApplyLevelKind) << 1) | !!IsCompoundName;
109+
}
110+
111+
/// Whether the function reference is part of a call, and if so how many
112+
/// applications were used.
113+
ApplyLevel getApplyLevel() const { return ApplyLevelKind; }
114+
115+
/// Whether the function was referenced using a compound name,
116+
/// e.g `fn(x:)(0)`.
117+
bool isCompoundName() const { return IsCompoundName; }
118+
119+
/// Whether the function reference is not part of a call.
120+
bool isUnapplied() const {
121+
return getApplyLevel() == ApplyLevel::Unapplied;
122+
}
123+
124+
/// Whether the function reference is both not part of a call, and is
125+
/// not using a compound name.
126+
bool isUnappliedBaseName() const {
127+
return getApplyLevel() == ApplyLevel::Unapplied && !isCompoundName();
128+
}
129+
130+
/// Whether the function reference has been applied a single time.
131+
bool isSingleApply() const {
132+
return getApplyLevel() == ApplyLevel::SingleApply;
133+
}
134+
135+
/// Whether the function reference has been applied twice.
136+
bool isDoubleApply() const {
137+
return getApplyLevel() == ApplyLevel::DoubleApply;
138+
}
139+
140+
/// Returns the FunctionRefInfo with an additional level of function
141+
/// application added.
142+
FunctionRefInfo addingApplicationLevel() const;
143+
144+
friend bool operator==(const FunctionRefInfo &lhs,
145+
const FunctionRefInfo &rhs) {
146+
return lhs.getApplyLevel() == rhs.getApplyLevel() &&
147+
lhs.isCompoundName() == rhs.isCompoundName();
148+
}
149+
friend bool operator!=(const FunctionRefInfo &lhs,
150+
const FunctionRefInfo &rhs) {
151+
return !(lhs == rhs);
152+
}
153+
154+
void dump(raw_ostream &os) const;
155+
SWIFT_DEBUG_DUMP;
156+
};
50157
}
51158

52159
#endif // SWIFT_AST_FUNCTION_REF_INFO_H

0 commit comments

Comments
 (0)