Verify that a function's DeclName, TuplePattern, and ParamDecls are in sync.

This required a few changes in places where we synthesize functions to
make sure these properties hold. That's good because we don't know where
we might already be depending on them. (On the other hand, we could also
decide not to care about TuplePattern labels, in which case I wonder if
we could eventually discard them altogether in functions.)

Still untested: that the function type is also in sync.
This commit is contained in:
Jordan Rose
2015-10-28 18:05:01 -07:00
parent 3a1fad6d55
commit 070ccba166
4 changed files with 90 additions and 3 deletions

View File

@@ -2117,6 +2117,87 @@ struct ASTNodeBase {};
void verifyChecked(AbstractFunctionDecl *AFD) {
PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD);
// All of the parameter names should match.
if (!isa<DestructorDecl>(AFD)) {
auto paramNames = AFD->getFullName().getArgumentNames();
bool checkParamNames = (bool)AFD->getFullName();
bool hasSelf = AFD->getDeclContext()->isTypeContext();
const Pattern *firstParams =
AFD->getBodyParamPatterns()[hasSelf ? 1 : 0];
if (auto *paramTuple = dyn_cast<TuplePattern>(firstParams)) {
if (checkParamNames &&
paramNames.size() != paramTuple->getNumElements()) {
Out << "Function name does not match its argument pattern ("
<< paramNames.size() << " elements instead of "
<< paramTuple->getNumElements() << ")\n";
AFD->dump(Out);
abort();
}
// This doesn't use for_each because paramNames shouldn't be checked
// when the function is anonymous.
for (size_t i = 0, e = paramTuple->getNumElements(); i < e; ++i) {
TuplePatternElt elt = paramTuple->getElement(i);
Pattern *param = elt.getPattern()->getSemanticsProvidingPattern();
if (auto *namedParam = dyn_cast<NamedPattern>(param)) {
if (namedParam->getBoundName() != elt.getLabel()) {
Out << "Function body param tuple label "
"doesn't match variable's public name\n";
AFD->dump(Out);
abort();
}
if (checkParamNames &&
namedParam->getBoundName() != paramNames[i]) {
Out << "Function full name doesn't match variable name\n";
AFD->dump(Out);
abort();
}
} else {
assert(isa<AnyPattern>(param));
if (!elt.getLabel().empty()) {
Out << "Function body param tuple has a label, "
"but there's no variable\n";
AFD->dump(Out);
abort();
}
if (checkParamNames && !paramNames[i].empty()) {
Out << "Function full name doesn't match variable name\n";
AFD->dump(Out);
abort();
}
}
}
} else {
if (checkParamNames && paramNames.size() != 1) {
Out << "Function name does not match its non-tuple argument pattern ("
<< paramNames.size() << " elements instead of 1)\n";
AFD->dump(Out);
abort();
}
firstParams = firstParams->getSemanticsProvidingPattern();
if (auto *namedParam = dyn_cast<NamedPattern>(firstParams)) {
if (checkParamNames &&
namedParam->getBoundName() != paramNames.front()) {
Out << "Function full name doesn't match variable name\n";
AFD->dump(Out);
abort();
}
} else {
assert(isa<AnyPattern>(firstParams));
if (checkParamNames && !paramNames.front().empty()) {
Out << "Function full name has an argument name, "
"but there's no variable\n";
AFD->dump(Out);
abort();
}
}
}
}
// If this function is generic or is within a generic type, it should
// have an interface type.
if ((AFD->getGenericParams() ||

View File

@@ -584,6 +584,7 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl,
paramPattern->setImplicit();
auto patternElt = TuplePatternElt(paramPattern);
patternElt.setLabel(C.Id_rawValue, SourceLoc());
paramPattern = TuplePattern::create(C, SourceLoc(), patternElt, SourceLoc());
paramPattern->setImplicit();
auto typeElt = TupleTypeElt(enumDecl->getRawType(), C.Id_rawValue);
@@ -1767,6 +1768,7 @@ namespace {
Pattern *pattern = createTypedNamedPattern(param);
paramPatterns.push_back(pattern);
patternElts.push_back(TuplePatternElt(pattern));
patternElts.back().setLabel(argName, SourceLoc());
tupleElts.push_back(TupleTypeElt(var->getType(), var->getName()));
}
auto paramPattern = TuplePattern::create(context, SourceLoc(), patternElts,

View File

@@ -1456,6 +1456,7 @@ Type ClangImporter::Implementation::importFunctionType(
TypeLoc::withoutLoc(swiftParamTy));
bodyPattern->setType(swiftParamTy);
bodyPatternElts.push_back(TuplePatternElt(bodyPattern));
bodyPatternElts.back().setLabel(name, SourceLoc());
// Add the tuple elements for the function types.
swiftArgParams.push_back(TupleTypeElt(swiftParamTy, name));
@@ -2316,6 +2317,7 @@ Type ClangImporter::Implementation::importMethodType(
pattern->setType(type);
bodyPatternElts.push_back(TuplePatternElt(pattern));
bodyPatternElts.back().setLabel(argName, SourceLoc());
swiftArgParams.push_back(TupleTypeElt(type, argName));
swiftBodyParams.push_back(TupleTypeElt(type, argName));
};
@@ -2463,6 +2465,7 @@ Type ClangImporter::Implementation::importMethodType(
bodyPattern->setType(swiftParamTy);
TuplePatternElt patternElt(bodyPattern);
patternElt.setDefaultArgKind(defaultArg);
patternElt.setLabel(name, SourceLoc());
bodyPatternElts.push_back(patternElt);
// Add the tuple elements for the function types.

View File

@@ -155,9 +155,10 @@ static Pattern *buildIndexForwardingPattern(AbstractStorageDecl *storage,
// Clone index patterns in a manner that allows them to be
// perfectly forwarded.
DeclContext *DC = storage->getDeclContext();
auto addVarPatternFor = [&](Pattern *P) {
auto addVarPatternFor = [&](Pattern *P, Identifier label = Identifier()) {
Pattern *vp = P->cloneForwardable(TC.Context, DC, Pattern::Implicit);
elements.push_back(TuplePatternElt(vp));
elements.back().setLabel(label, SourceLoc());
};
// This is the same breakdown the parser does.
@@ -167,7 +168,7 @@ static Pattern *buildIndexForwardingPattern(AbstractStorageDecl *storage,
} else {
auto tp = cast<TuplePattern>(indices);
for (auto &element : tp->getElements()) {
addVarPatternFor(element.getPattern());
addVarPatternFor(element.getPattern(), element.getLabel());
}
}