Skip to content

Commit fb276d3

Browse files
Chris LattnerChris Lattner
authored andcommitted
fill out the Parameter and ParameterList APIs and implementation to be a lot
closer to what we need. NFC since there are no clients yet.
1 parent b178839 commit fb276d3

File tree

2 files changed

+283
-8
lines changed

2 files changed

+283
-8
lines changed

include/swift/AST/Parameter.h

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include "swift/AST/DefaultArgumentKind.h"
2222
#include "swift/AST/TypeLoc.h"
23+
#include "swift/AST/Decl.h"
24+
#include "swift/Basic/OptionSet.h"
2325

2426
namespace swift {
2527
class ParamDecl;
@@ -33,8 +35,8 @@ namespace swift {
3335
/// a : Int = 42 //< Default value.
3436
/// a : Int... //< Varargs parameter.
3537
///
36-
/// Parameters are stored in parameter lists, and multiple levels of currying
37-
/// are represented with multiple parameter lists.
38+
/// A parameter is stored as ParamDecls with additional information in the
39+
/// Parameter struct to represent source information as well as extra semantics.
3840
///
3941
struct Parameter {
4042
/// The decl keeps track of the internal and external parameter name, as well
@@ -51,16 +53,50 @@ struct Parameter {
5153
// an Expr* here, along with a "is checked" bit.
5254

5355
/// The default value, if any, along with whether this is varargs.
54-
llvm::PointerIntPair<ExprHandle *, 1, bool> defaultValueAndIsVarargs;
56+
llvm::PointerIntPair<ExprHandle *, 1, bool> defaultValueAndIsVariadic;
5557

58+
void setDefaultValue(ExprHandle *H) {
59+
defaultValueAndIsVariadic.setPointer(H);
60+
}
5661
ExprHandle *getDefaultValue() const {
57-
return defaultValueAndIsVarargs.getPointer();
62+
return defaultValueAndIsVariadic.getPointer();
5863
}
5964
/// Whether or not this parameter is varargs.
60-
bool isVarargs() const { return defaultValueAndIsVarargs.getInt(); }
65+
bool isVariadic() const { return defaultValueAndIsVariadic.getInt(); }
66+
void setVariadic(bool value = true) {defaultValueAndIsVariadic.setInt(value);}
6167

6268
/// Information about a symbolic default argument, like __FILE__.
6369
DefaultArgumentKind defaultArgumentKind;
70+
71+
/// Remove the type of this varargs element designator, without the array
72+
/// type wrapping it. A parameter like "Int..." will have formal parameter
73+
/// type of "[Int]" and this returns "Int".
74+
static Type getVarargBaseTy(Type VarArgT);
75+
76+
/// Remove the type of this varargs element designator, without the array
77+
/// type wrapping it.
78+
Type getVarargBaseTy() const {
79+
assert(isVariadic());
80+
return getVarargBaseTy(decl->getType());
81+
}
82+
83+
/// Create a simple parameter without location information.
84+
static Parameter withoutLoc(ParamDecl *decl) {
85+
Parameter result;
86+
result.decl = decl;
87+
result.type = TypeLoc::withoutLoc(decl->getType());
88+
return result;
89+
}
90+
91+
/// Return the full source range of this parameter.
92+
SourceRange getSourceRange() const;
93+
SourceLoc getStartLoc() const { return getSourceRange().Start; }
94+
SourceLoc getEndLoc() const { return getSourceRange().End; }
95+
96+
void dump() const;
97+
void dump(raw_ostream &OS, unsigned Indent = 0) const;
98+
99+
// void print(raw_ostream &OS) const;
64100
};
65101

66102

@@ -73,12 +109,49 @@ class alignas(alignof(Parameter)) ParameterList {
73109
void *operator new(size_t Bytes, ASTContext &C,
74110
unsigned Alignment = 8);
75111

112+
SourceLoc LParenLoc, RParenLoc;
76113
size_t numParameters;
77114

78115
ParameterList(size_t numParameters) : numParameters(numParameters) {}
79116
void operator=(const ParameterList&) = delete;
80117
public:
81-
static ParameterList *create(ASTContext &Context, ArrayRef<Parameter> Params);
118+
/// Create a parameter list with the specified parameters.
119+
static ParameterList *create(const ASTContext &C, SourceLoc LParenLoc,
120+
ArrayRef<Parameter> params,
121+
SourceLoc RParenLoc);
122+
123+
/// Create a parameter list with the specified parameters, with no location
124+
/// info for the parens.
125+
static ParameterList *create(const ASTContext &C,
126+
ArrayRef<Parameter> params) {
127+
return create(C, SourceLoc(), params, SourceLoc());
128+
}
129+
130+
/// Create an empty parameter list.
131+
static ParameterList *createEmpty(const ASTContext &C,
132+
SourceLoc LParenLoc = SourceLoc(),
133+
SourceLoc RParenLoc = SourceLoc()) {
134+
return create(C, LParenLoc, {}, RParenLoc);
135+
}
136+
137+
/// Create a parameter list for a single parameter lacking location info.
138+
static ParameterList *createWithoutLoc(ParamDecl *decl) {
139+
return create(decl->getASTContext(), Parameter::withoutLoc(decl));
140+
}
141+
142+
/// Create an implicit 'self' decl for a method in the specified decl context.
143+
/// If 'static' is true, then this is self for a static method in the type.
144+
///
145+
/// Note that this decl is created, but it is returned with an incorrect
146+
/// DeclContext that needs to be set correctly. This is automatically handled
147+
/// when a function is created with this as part of its argument list.
148+
///
149+
static ParameterList *createSelf(SourceLoc loc, DeclContext *DC,
150+
bool isStaticMethod = false,
151+
bool isInOut = false);
152+
153+
SourceLoc getLParenLoc() const { return LParenLoc; }
154+
SourceLoc getRParenLoc() const { return RParenLoc; }
82155

83156
size_t getNumParameters() const {
84157
return numParameters;
@@ -100,6 +173,46 @@ class alignas(alignof(Parameter)) ParameterList {
100173
Parameter &getParameter(unsigned i) {
101174
return getParameters()[i];
102175
}
176+
177+
/// Change the DeclContext of any contained parameters to the specified
178+
/// DeclContext.
179+
void setDeclContextOfParamDecls(DeclContext *DC);
180+
181+
182+
/// Flags used to indicate how ParameterList cloning should operate.
183+
enum CloneFlags {
184+
/// The cloned ParamDecls should be marked implicit.
185+
Implicit = 0x01,
186+
/// The cloned pattern is for an inherited constructor; mark default
187+
/// arguments as inherited, and mark unnamed arguments as named.
188+
Inherited = 0x02
189+
};
190+
191+
/// Make a duplicate copy of this parameter list. This allocates copies of
192+
/// the ParamDecls, so they can be reparented into a new DeclContext.
193+
ParameterList *clone(const ASTContext &C,
194+
OptionSet<CloneFlags> options = None) const;
195+
196+
/// Return a TupleType or ParenType for this parameter list. This returns a
197+
/// null type if one of the ParamDecls does not have a type set for it yet.
198+
Type getType(const ASTContext &C) const;
199+
200+
/// Return the full function type for a set of curried parameter lists that
201+
/// returns the specified result type. This returns a null type if one of the
202+
/// ParamDecls does not have a type set for it yet.
203+
///
204+
static Type getFullType(Type resultType, ArrayRef<ParameterList*> PL);
205+
206+
207+
/// Return the full source range of this parameter.
208+
SourceRange getSourceRange() const;
209+
SourceLoc getStartLoc() const { return getSourceRange().Start; }
210+
SourceLoc getEndLoc() const { return getSourceRange().End; }
211+
212+
void dump() const;
213+
void dump(raw_ostream &OS, unsigned Indent = 0) const;
214+
215+
// void print(raw_ostream &OS) const;
103216
};
104217

105218
} // end namespace swift.

lib/AST/Parameter.cpp

Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,58 @@
1717

1818
#include "swift/AST/Parameter.h"
1919
#include "swift/AST/ASTContext.h"
20+
#include "swift/AST/Expr.h"
21+
#include "swift/AST/ExprHandle.h"
2022
using namespace swift;
2123

24+
/// Return the full source range of this parameter.
25+
SourceRange Parameter::getSourceRange() const {
26+
SourceRange range = decl->getSourceRange();
27+
if (range.isInvalid()) return range;
28+
29+
// It would be nice to extend the front of the range to show where inout is,
30+
// but we don't have that location info. Extend the back of the range to the
31+
// location of the default argument, or the typeloc if they are valid.
32+
if (auto expr = getDefaultValue()) {
33+
auto endLoc = expr->getExpr()->getEndLoc();
34+
if (endLoc.isValid())
35+
return SourceRange(range.Start, endLoc);
36+
}
37+
38+
// If the typeloc has a valid location, use it to end the range.
39+
if (auto typeRepr = type.getTypeRepr()) {
40+
auto endLoc = typeRepr->getEndLoc();
41+
if (endLoc.isValid())
42+
return SourceRange(range.Start, endLoc);
43+
}
44+
45+
// Otherwise, just return the info we have about the parameter.
46+
return range;
47+
}
48+
49+
Type Parameter::getVarargBaseTy(Type VarArgT) {
50+
TypeBase *T = VarArgT.getPointer();
51+
if (ArraySliceType *AT = dyn_cast<ArraySliceType>(T))
52+
return AT->getBaseType();
53+
if (BoundGenericType *BGT = dyn_cast<BoundGenericType>(T)) {
54+
// It's the stdlib Array<T>.
55+
return BGT->getGenericArgs()[0];
56+
}
57+
assert(isa<ErrorType>(T));
58+
return T;
59+
}
60+
61+
2262
/// TODO: unique and reuse the () parameter list in ASTContext, as well as the
2363
/// "(self : T)" parameter lists common to many methods.
2464
ParameterList *
25-
ParameterList::create(ASTContext &context, ArrayRef<Parameter> params) {
65+
ParameterList::create(const ASTContext &C, SourceLoc LParenLoc,
66+
ArrayRef<Parameter> params, SourceLoc RParenLoc) {
67+
assert(LParenLoc.isValid() == RParenLoc.isValid() &&
68+
"Either both paren locs are valid or neither are");
69+
2670
auto byteSize = sizeof(ParameterList)+params.size()*sizeof(Parameter);
27-
auto rawMem = context.Allocate(byteSize, alignof(ParameterList));
71+
auto rawMem = C.Allocate(byteSize, alignof(ParameterList));
2872

2973
// Placement initialize the ParameterList and the Parameter's.
3074
auto PL = ::new (rawMem) ParameterList(params.size());
@@ -34,3 +78,121 @@ ParameterList::create(ASTContext &context, ArrayRef<Parameter> params) {
3478

3579
return PL;
3680
}
81+
82+
/// Create an implicit 'self' decl for a method in the specified decl context.
83+
/// If 'static' is true, then this is self for a static method in the type.
84+
///
85+
/// Note that this decl is created, but it is returned with an incorrect
86+
/// DeclContext that needs to be set correctly. This is automatically handled
87+
/// when a function is created with this as part of its argument list.
88+
///
89+
ParameterList *ParameterList::createSelf(SourceLoc loc, DeclContext *DC,
90+
bool isStaticMethod, bool isInOut) {
91+
auto *param = ParamDecl::createSelf(loc, DC, isStaticMethod, isInOut);
92+
return create(DC->getASTContext(), Parameter::withoutLoc(param));
93+
}
94+
95+
/// Change the DeclContext of any contained parameters to the specified
96+
/// DeclContext.
97+
void ParameterList::setDeclContextOfParamDecls(DeclContext *DC) {
98+
for (auto &P : getParameters())
99+
P.decl->setDeclContext(DC);
100+
}
101+
102+
103+
104+
/// Make a duplicate copy of this parameter list. This allocates copies of
105+
/// the ParamDecls, so they can be reparented into a new DeclContext.
106+
ParameterList *ParameterList::clone(const ASTContext &C,
107+
OptionSet<CloneFlags> options) const {
108+
// If this list is empty, don't actually bother with a copy.
109+
if (getNumParameters() == 0)
110+
return const_cast<ParameterList*>(this);
111+
112+
SmallVector<Parameter, 8> params(getParameters().begin(),
113+
getParameters().end());
114+
115+
// Remap the ParamDecls inside of the ParameterList.
116+
for (auto &param : params) {
117+
auto decl = param.decl;
118+
auto name = decl->getName();
119+
// If the argument isn't named, and we're cloning for an inherited
120+
// constructor, give the parameter a name so that silgen will produce a
121+
// value for it.
122+
if (name.empty() && (options & Inherited))
123+
name = C.getIdentifier("argument");
124+
125+
param.decl = new (C) ParamDecl(decl->isLet(),
126+
decl->getArgumentNameLoc(),
127+
decl->getArgumentName(),
128+
decl->getLoc(), name,
129+
decl->hasType() ? decl->getType() : Type(),
130+
decl->getDeclContext());
131+
if ((options & Implicit) || decl->isImplicit())
132+
param.decl->setImplicit();
133+
134+
// If we're inheriting a default argument, mark it as such.
135+
if (param.defaultArgumentKind != DefaultArgumentKind::None &&
136+
(options & Inherited)) {
137+
param.defaultArgumentKind = DefaultArgumentKind::Inherited;
138+
param.setDefaultValue(nullptr);
139+
}
140+
}
141+
142+
return create(C, getParameters());
143+
}
144+
145+
/// Return a TupleType or ParenType for this parameter list. This returns a
146+
/// null type if one of the ParamDecls does not have a type set for it yet.
147+
Type ParameterList::getType(const ASTContext &C) const {
148+
if (getNumParameters() == 0)
149+
return TupleType::getEmpty(C);
150+
151+
SmallVector<TupleTypeElt, 8> argumentInfo;
152+
153+
for (auto &P : getParameters()) {
154+
if (!P.decl->hasType()) return Type();
155+
156+
argumentInfo.push_back({
157+
P.decl->getType(), P.decl->getArgumentName(), P.defaultArgumentKind,
158+
P.isVariadic()
159+
});
160+
}
161+
162+
return TupleType::get(argumentInfo, C);
163+
}
164+
165+
166+
/// Return the full function type for a set of curried parameter lists that
167+
/// returns the specified result type. This returns a null type if one of the
168+
/// ParamDecls does not have a type set for it yet.
169+
///
170+
Type ParameterList::getFullType(Type resultType, ArrayRef<ParameterList*> PLL) {
171+
auto result = resultType;
172+
auto &C = result->getASTContext();
173+
174+
for (auto PL : reversed(PLL)) {
175+
auto paramType = PL->getType(C);
176+
if (!paramType) return Type();
177+
result = FunctionType::get(paramType, result);
178+
}
179+
return result;
180+
}
181+
182+
/// Return the full source range of this parameter list.
183+
SourceRange ParameterList::getSourceRange() const {
184+
// If we have locations for the parens, then they define our range.
185+
if (LParenLoc.isValid())
186+
return { LParenLoc, RParenLoc };
187+
188+
// Otherwise, try the first and last parameter.
189+
if (getNumParameters() != 0) {
190+
auto Start = getParameter(0).getStartLoc();
191+
auto End = getParameters().back().getEndLoc();
192+
if (Start.isValid() && End.isValid())
193+
return { Start, End };
194+
}
195+
196+
return SourceRange();
197+
}
198+

0 commit comments

Comments
 (0)