Skip to content

[Sema] Consolidate logic for whether a decl has a curried self or parameter list #25170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 18, 2019
Merged
26 changes: 25 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2705,6 +2705,15 @@ class ValueDecl : public Decl {
/// curried self parameter.
bool hasCurriedSelf() const;

/// Returns true if the declaration has a parameter list associated with it.
///
/// Note that not all declarations with function interface types have
/// parameter lists, for example an enum element without associated values.
bool hasParameterList() const;

/// Returns the number of curry levels in the declaration's interface type.
unsigned getNumCurryLevels() const;

/// Get the decl for this value's opaque result type, if it has one.
OpaqueTypeDecl *getOpaqueResultTypeDecl() const;

Expand Down Expand Up @@ -7201,6 +7210,21 @@ inline bool ValueDecl::hasCurriedSelf() const {
return false;
}

inline bool ValueDecl::hasParameterList() const {
if (auto *eed = dyn_cast<EnumElementDecl>(this))
return eed->hasAssociatedValues();
return isa<AbstractFunctionDecl>(this) || isa<SubscriptDecl>(this);
}

inline unsigned ValueDecl::getNumCurryLevels() const {
unsigned curryLevels = 0;
if (hasParameterList())
curryLevels++;
if (hasCurriedSelf())
curryLevels++;
return curryLevels;
}

inline bool Decl::isPotentiallyOverridable() const {
if (isa<VarDecl>(this) ||
isa<SubscriptDecl>(this) ||
Expand Down Expand Up @@ -7265,7 +7289,7 @@ inline EnumElementDecl *EnumDecl::getUniqueElement(bool hasValue) const {
}

/// Retrieve parameter declaration from the given source at given index.
const ParamDecl *getParameterAt(ValueDecl *source, unsigned index);
const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);

/// Display Decl subclasses.
void simple_display(llvm::raw_ostream &out, const Decl *decl);
Expand Down
8 changes: 4 additions & 4 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2400,7 +2400,7 @@ CanType ValueDecl::getOverloadSignatureType() const {
/*topLevelFunction=*/true,
isMethod,
/*isInitializer=*/isa<ConstructorDecl>(afd),
isMethod ? 2 : 1)->getCanonicalType();
getNumCurryLevels())->getCanonicalType();
}

if (isa<AbstractStorageDecl>(this)) {
Expand All @@ -2416,7 +2416,7 @@ CanType ValueDecl::getOverloadSignatureType() const {
/*topLevelFunction=*/true,
/*isMethod=*/false,
/*isInitializer=*/false,
1)->getCanonicalType();
getNumCurryLevels())->getCanonicalType();
}

// We want to curry the default signature type with the 'self' type of the
Expand All @@ -2430,7 +2430,7 @@ CanType ValueDecl::getOverloadSignatureType() const {
if (isa<EnumElementDecl>(this)) {
auto mappedType = mapSignatureFunctionType(
getASTContext(), getInterfaceType(), /*topLevelFunction=*/false,
/*isMethod=*/false, /*isInitializer=*/false, /*curryLevels=*/0);
/*isMethod=*/false, /*isInitializer=*/false, getNumCurryLevels());
return mappedType->getCanonicalType();
}

Expand Down Expand Up @@ -6108,7 +6108,7 @@ DeclName AbstractFunctionDecl::getEffectiveFullName() const {
return DeclName();
}

const ParamDecl *swift::getParameterAt(ValueDecl *source, unsigned index) {
const ParamDecl *swift::getParameterAt(const ValueDecl *source, unsigned index) {
const ParameterList *paramList;
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(source)) {
paramList = AFD->getParameters();
Expand Down
10 changes: 2 additions & 8 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,14 +317,8 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const {
if (isa<DefaultArgumentInitializer>(dc)) {
dc = dc->getParent();

const ValueDecl *VD;
if (auto *FD = dyn_cast<AbstractFunctionDecl>(dc)) {
VD = FD;
} else if (auto *EED = dyn_cast<EnumElementDecl>(dc)) {
VD = EED;
} else {
VD = cast<SubscriptDecl>(dc);
}
auto *VD = cast<ValueDecl>(dc->getAsDecl());
assert(VD->hasParameterList());

auto access =
VD->getFormalAccessScope(/*useDC=*/nullptr,
Expand Down
20 changes: 10 additions & 10 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,26 +743,26 @@ ParameterListInfo::ParameterListInfo(
if (!paramOwner)
return;

// If the decl has a curried self, but we're not allowed to skip it, return.
if (paramOwner->hasCurriedSelf() && !skipCurriedSelf)
return;

// Find the corresponding parameter list.
const ParameterList *paramList = nullptr;
if (auto *func = dyn_cast<AbstractFunctionDecl>(paramOwner)) {
if (func->hasImplicitSelfDecl()) {
if (skipCurriedSelf)
paramList = func->getParameters();
} else if (!skipCurriedSelf)
paramList = func->getParameters();
paramList = func->getParameters();
} else if (auto *subscript = dyn_cast<SubscriptDecl>(paramOwner)) {
if (skipCurriedSelf)
paramList = subscript->getIndices();
paramList = subscript->getIndices();
} else if (auto *enumElement = dyn_cast<EnumElementDecl>(paramOwner)) {
if (skipCurriedSelf)
paramList = enumElement->getParameterList();
paramList = enumElement->getParameterList();
}

// No parameter list means no default arguments - hand back the zeroed
// bitvector.
if (!paramList)
if (!paramList) {
assert(!paramOwner->hasParameterList());
return;
}

switch (params.size()) {
case 0:
Expand Down
2 changes: 1 addition & 1 deletion lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ protocolForLiteralKind(CodeCompletionLiteralKind kind) {
static bool hasTrivialTrailingClosure(const FuncDecl *FD,
AnyFunctionType *funcType) {
ParameterListInfo paramInfo(funcType->getParams(), FD,
/*level*/ FD->isInstanceMember() ? 1 : 0);
/*skipCurriedSelf*/ FD->hasCurriedSelf());

if (paramInfo.size() - paramInfo.numNonDefaultedParameters() == 1) {
auto param = funcType->getParams().back();
Expand Down
11 changes: 1 addition & 10 deletions lib/ParseSIL/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2028,18 +2028,9 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired) {
for (unsigned I = 0, E = values.size(); I < E; I++) {
auto *decl = values[I];

unsigned numArgumentLabels = 0;
if (auto *eed = dyn_cast<EnumElementDecl>(decl)) {
numArgumentLabels =
(eed->hasAssociatedValues() ? 2 : 1);
} else if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
numArgumentLabels =
(decl->getDeclContext()->isTypeContext() ? 2 : 1);
}

auto lookupTy =
decl->getInterfaceType()
->removeArgumentLabels(numArgumentLabels);
->removeArgumentLabels(decl->getNumCurryLevels());
if (declTy == lookupTy->getCanonicalType()) {
TheDecl = decl;
// Update SILDeclRef to point to the right Decl.
Expand Down
8 changes: 4 additions & 4 deletions lib/SIL/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1018,10 +1018,10 @@ unsigned SILDeclRef::getParameterListCount() const {

auto *vd = getDecl();

if (auto *func = dyn_cast<AbstractFunctionDecl>(vd)) {
return func->hasImplicitSelfDecl() ? 2 : 1;
} else if (auto *ed = dyn_cast<EnumElementDecl>(vd)) {
return ed->hasAssociatedValues() ? 2 : 1;
if (isa<AbstractFunctionDecl>(vd) || isa<EnumElementDecl>(vd)) {
// For functions and enum elements, the number of parameter lists is the
// same as in their interface type.
return vd->getNumCurryLevels();
} else if (isa<ClassDecl>(vd)) {
return 2;
} else if (isa<VarDecl>(vd)) {
Expand Down
11 changes: 4 additions & 7 deletions lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2663,8 +2663,7 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType,
// default arguments.
ParameterListInfo paramInfo;
if (!candidates.empty()) {
paramInfo = ParameterListInfo(params, candidates[0].getDecl(),
candidates[0].skipCurriedSelf);
paramInfo = candidates[0].getParameterListInfo(params);
} else {
paramInfo = ParameterListInfo(params, nullptr, /*skipCurriedSelf=*/false);
}
Expand Down Expand Up @@ -3550,8 +3549,7 @@ diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, Expr *fnExpr,
return false;

auto params = candidate.getParameters();
ParameterListInfo paramInfo(params, candidate.getDecl(),
candidate.skipCurriedSelf);
auto paramInfo = candidate.getParameterListInfo(params);
auto args = decomposeArgType(CCI.CS.getType(argExpr), argLabels);

// Check the case where a raw-representable type is constructed from an
Expand Down Expand Up @@ -4198,8 +4196,7 @@ bool FailureDiagnosis::diagnoseArgumentGenericRequirements(
return false;

auto params = candidate.getParameters();
ParameterListInfo paramInfo(params, candidate.getDecl(),
candidate.skipCurriedSelf);
auto paramInfo = candidate.getParameterListInfo(params);
auto args = decomposeArgType(CS.getType(argExpr), argLabels);

SmallVector<ParamBinding, 4> bindings;
Expand Down Expand Up @@ -4672,7 +4669,7 @@ static bool isViableOverloadSet(const CalleeCandidateInfo &CCI,
return true;
};

ParameterListInfo paramInfo(params, funcDecl, cand.skipCurriedSelf);
auto paramInfo = cand.getParameterListInfo(params);
InputMatcher IM(params, paramInfo);
auto result = IM.match(numArgs, pairMatcher);
if (result == InputMatcher::IM_Succeeded)
Expand Down
62 changes: 14 additions & 48 deletions lib/Sema/CSRanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,20 +367,9 @@ static Type getAdjustedParamType(const AnyFunctionType::Param &param) {

// Is a particular parameter of a function or subscript declaration
// declared to be an IUO?
static bool paramIsIUO(Decl *decl, int paramNum) {
if (auto *fn = dyn_cast<AbstractFunctionDecl>(decl)) {
auto *paramList = fn->getParameters();
auto *param = paramList->get(paramNum);
return param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
}
if (auto *ee = dyn_cast<EnumElementDecl>(decl)) {
auto *param = ee->getParameterList()->get(paramNum);
return param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
}

auto *subscript = cast<SubscriptDecl>(decl);
auto *index = subscript->getIndices()->get(paramNum);
return index->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
static bool paramIsIUO(const ValueDecl *decl, int paramNum) {
return swift::getParameterAt(decl, paramNum)->getAttrs()
.hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
}

/// Determine whether the first declaration is as "specialized" as
Expand Down Expand Up @@ -479,30 +468,12 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
Type type1 = decl1->getInterfaceType();
Type type2 = decl2->getInterfaceType();

/// What part of the type should we check?
enum {
CheckAll,
CheckInput,
} checkKind;
if (isa<AbstractFunctionDecl>(decl1) || isa<EnumElementDecl>(decl1)) {
// Nothing to do: these have the curried 'self' already.
if (auto elt = dyn_cast<EnumElementDecl>(decl1)) {
checkKind = elt->hasAssociatedValues() ? CheckInput : CheckAll;
} else {
checkKind = CheckInput;
}
} else {
// Add a curried 'self' type.
// Add curried 'self' types if necessary.
if (!decl1->hasCurriedSelf())
type1 = type1->addCurriedSelfType(outerDC1);
type2 = type2->addCurriedSelfType(outerDC2);

// For a subscript declaration, only look at the input type (i.e., the
// indices).
if (isa<SubscriptDecl>(decl1))
checkKind = CheckInput;
else
checkKind = CheckAll;
}
if (!decl2->hasCurriedSelf())
type2 = type2->addCurriedSelfType(outerDC2);

auto openType = [&](ConstraintSystem &cs, DeclContext *innerDC,
DeclContext *outerDC, Type type,
Expand Down Expand Up @@ -600,18 +571,16 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
}

bool fewerEffectiveParameters = false;
switch (checkKind) {
case CheckAll:
// Check whether the first type is a subtype of the second.
if (!decl1->hasParameterList() && !decl2->hasParameterList()) {
// If neither decl has a parameter list, simply check whether the first
// type is a subtype of the second.
cs.addConstraint(ConstraintKind::Subtype,
openedType1,
openedType2,
locator);
break;

case CheckInput: {
// Check whether the first function type's input is a subtype of the
// second type's inputs, i.e., can we forward the arguments?
} else if (decl1->hasParameterList() && decl2->hasParameterList()) {
// Otherwise, check whether the first function type's input is a subtype
// of the second type's inputs, i.e., can we forward the arguments?
auto funcTy1 = openedType1->castTo<FunctionType>();
auto funcTy2 = openedType2->castTo<FunctionType>();
auto params1 = funcTy1->getParams();
Expand Down Expand Up @@ -669,7 +638,7 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
};

ParameterListInfo paramInfo(
params2, decl2, decl2->getDeclContext()->isTypeContext());
params2, decl2, decl2->hasCurriedSelf());
auto params2ForMatching = params2;
if (compareTrailingClosureParamsSeparately) {
--numParams1;
Expand All @@ -685,9 +654,6 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
if (compareTrailingClosureParamsSeparately)
if (!maybeAddSubtypeConstraint(params1.back(), params2.back()))
knownNonSubtype = true;

break;
}
}

if (!knownNonSubtype) {
Expand Down
Loading