Skip to content

Improve -debug-constraints output for key path components #24084

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 6 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace swift {
class ParameterList;
class EnumElementDecl;
class CallExpr;
class KeyPathExpr;

enum class ExprKind : uint8_t {
#define EXPR(Id, Parent) Id,
Expand Down Expand Up @@ -539,6 +540,7 @@ class alignas(8) Expr {
void dump(raw_ostream &OS, unsigned Indent = 0) const;
void dump(raw_ostream &OS, llvm::function_ref<Type(const Expr *)> getType,
llvm::function_ref<Type(const TypeLoc &)> getTypeOfTypeLoc,
llvm::function_ref<Type(const KeyPathExpr *E, unsigned index)> getTypeOfKeyPathComponent,
unsigned Indent = 0) const;

void print(ASTPrinter &Printer, const PrintOptions &Opts) const;
Expand Down
94 changes: 56 additions & 38 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1727,14 +1727,17 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
raw_ostream &OS;
llvm::function_ref<Type(const Expr *)> GetTypeOfExpr;
llvm::function_ref<Type(const TypeLoc &)> GetTypeOfTypeLoc;
llvm::function_ref<Type(const KeyPathExpr *E, unsigned index)> GetTypeOfKeyPathComponent;
unsigned Indent;

PrintExpr(raw_ostream &os,
llvm::function_ref<Type(const Expr *)> getTypeOfExpr,
llvm::function_ref<Type(const TypeLoc &)> getTypeOfTypeLoc,
llvm::function_ref<Type(const KeyPathExpr *E, unsigned index)> getTypeOfKeyPathComponent,
unsigned indent)
: OS(os), GetTypeOfExpr(getTypeOfExpr),
GetTypeOfTypeLoc(getTypeOfTypeLoc), Indent(indent) {}
GetTypeOfTypeLoc(getTypeOfTypeLoc),
GetTypeOfKeyPathComponent(getTypeOfKeyPathComponent), Indent(indent) {}

void printRec(Expr *E) {
Indent += 2;
Expand Down Expand Up @@ -2612,83 +2615,94 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
printCommon(E, "keypath_expr");
if (E->isObjC())
OS << " objc";
for (auto &component : E->getComponents()) {

OS << '\n';
Indent += 2;
OS.indent(Indent);
PrintWithColorRAII(OS, ParenthesisColor) << '(';
PrintWithColorRAII(OS, ExprColor) << "components";
OS.indent(Indent + 2);
for (unsigned i : indices(E->getComponents())) {
auto &component = E->getComponents()[i];
OS << '\n';
OS.indent(Indent + 2);
OS << "(component=";
PrintWithColorRAII(OS, ParenthesisColor) << '(';
switch (component.getKind()) {
case KeyPathExpr::Component::Kind::Invalid:
OS << "invalid ";
PrintWithColorRAII(OS, ASTNodeColor) << "invalid";
break;

case KeyPathExpr::Component::Kind::OptionalChain:
OS << "optional_chain ";
PrintWithColorRAII(OS, ASTNodeColor) << "optional_chain";
break;

case KeyPathExpr::Component::Kind::OptionalForce:
OS << "optional_force ";
PrintWithColorRAII(OS, ASTNodeColor) << "optional_force";
break;

case KeyPathExpr::Component::Kind::OptionalWrap:
OS << "optional_wrap ";
PrintWithColorRAII(OS, ASTNodeColor) << "optional_wrap";
break;

case KeyPathExpr::Component::Kind::Property:
OS << "property ";
PrintWithColorRAII(OS, ASTNodeColor) << "property";
PrintWithColorRAII(OS, DeclColor) << " decl=";
printDeclRef(component.getDeclRef());
OS << " ";
break;

case KeyPathExpr::Component::Kind::Subscript:
OS << "subscript ";
PrintWithColorRAII(OS, ASTNodeColor) << "subscript";
PrintWithColorRAII(OS, DeclColor) << " decl='";
printDeclRef(component.getDeclRef());
OS << '\n';
component.getIndexExpr()->dump(OS, Indent + 4);
OS.indent(Indent + 4);
PrintWithColorRAII(OS, DeclColor) << "'";
break;

case KeyPathExpr::Component::Kind::UnresolvedProperty:
OS << "unresolved_property ";
component.getUnresolvedDeclName().print(OS);
OS << " ";
PrintWithColorRAII(OS, ASTNodeColor) << "unresolved_property";
PrintWithColorRAII(OS, IdentifierColor)
<< " decl_name='" << component.getUnresolvedDeclName() << "'";
break;

case KeyPathExpr::Component::Kind::UnresolvedSubscript:
OS << "unresolved_subscript";
OS << '\n';
component.getIndexExpr()->dump(OS, Indent + 4);
OS.indent(Indent + 4);
PrintWithColorRAII(OS, ASTNodeColor) << "unresolved_subscript";
printArgumentLabels(component.getSubscriptLabels());
break;
case KeyPathExpr::Component::Kind::Identity:
OS << "identity";
OS << '\n';
PrintWithColorRAII(OS, ASTNodeColor) << "identity";
break;

case KeyPathExpr::Component::Kind::TupleElement:
OS << "tuple_element ";
OS << "#" << component.getTupleIndex();
OS << " ";
PrintWithColorRAII(OS, ASTNodeColor) << "tuple_element ";
PrintWithColorRAII(OS, DiscriminatorColor)
<< "#" << component.getTupleIndex();
break;
}
OS << "type=";
component.getComponentType().print(OS);
PrintWithColorRAII(OS, TypeColor)
<< " type='" << GetTypeOfKeyPathComponent(E, i) << "'";
if (auto indexExpr = component.getIndexExpr()) {
OS << '\n';
Indent += 2;
printRec(indexExpr);
Indent -= 2;
}
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

PrintWithColorRAII(OS, ParenthesisColor) << ')';
Indent -= 2;

if (auto stringLiteral = E->getObjCStringLiteralExpr()) {
OS << '\n';
printRec(stringLiteral);
printRecLabeled(stringLiteral, "objc_string_literal");
}
if (!E->isObjC()) {
OS << "\n";
if (auto root = E->getParsedRoot()) {
printRec(root);
} else {
OS.indent(Indent + 2) << "<<null>>";
OS << "\n";
printRecLabeled(root, "parsed_root");
}
OS << "\n";
if (auto path = E->getParsedPath()) {
printRec(path);
} else {
OS.indent(Indent + 2) << "<<null>>";
OS << "\n";
printRecLabeled(path, "parsed_path");
}
}
PrintWithColorRAII(OS, ParenthesisColor) << ')';
Expand Down Expand Up @@ -2723,8 +2737,9 @@ void Expr::dump() const {
void Expr::dump(raw_ostream &OS,
llvm::function_ref<Type(const Expr *)> getTypeOfExpr,
llvm::function_ref<Type(const TypeLoc &)> getTypeOfTypeLoc,
llvm::function_ref<Type(const KeyPathExpr *E, unsigned index)> getTypeOfKeyPathComponent,
unsigned Indent) const {
PrintExpr(OS, getTypeOfExpr, getTypeOfTypeLoc, Indent)
PrintExpr(OS, getTypeOfExpr, getTypeOfTypeLoc, getTypeOfKeyPathComponent, Indent)
.visit(const_cast<Expr *>(this));
}

Expand All @@ -2733,7 +2748,10 @@ void Expr::dump(raw_ostream &OS, unsigned Indent) const {
auto getTypeOfTypeLoc = [](const TypeLoc &TL) -> Type {
return TL.getType();
};
dump(OS, getTypeOfExpr, getTypeOfTypeLoc, Indent);
auto getTypeOfKeyPathComponent = [](const KeyPathExpr *E, unsigned index) -> Type {
return E->getComponents()[index].getComponentType();
};
dump(OS, getTypeOfExpr, getTypeOfTypeLoc, getTypeOfKeyPathComponent, Indent);
}

void Expr::print(ASTPrinter &Printer, const PrintOptions &Opts) const {
Expand Down
18 changes: 17 additions & 1 deletion lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1698,9 +1698,12 @@ namespace {
}

assert(componentExpr);
componentExpr->setType(simplifyType(cs.getType(anchor)));
Type ty = simplifyType(cs.getType(anchor));
componentExpr->setType(ty);
cs.cacheType(componentExpr);

cs.setType(keyPath, 0, ty);

keyPath->setParsedPath(componentExpr);
keyPath->resolveComponents(ctx, {component});
return keyPath;
Expand Down Expand Up @@ -4358,6 +4361,13 @@ namespace {
Type baseTy = keyPathTy->getGenericArgs()[0];
Type leafTy = keyPathTy->getGenericArgs()[1];

// Updates the constraint system with the type of the last resolved
// component. We do it this way because we sometimes insert new
// components.
auto updateCSWithResolvedComponent = [&]() {
cs.setType(E, resolvedComponents.size() - 1, baseTy);
};

for (unsigned i : indices(E->getComponents())) {
auto &origComponent = E->getMutableComponents()[i];

Expand Down Expand Up @@ -4434,6 +4444,7 @@ namespace {
resolvedComponents.push_back(component);

if (shouldForceUnwrapResult(foundDecl->choice, locator)) {
updateCSWithResolvedComponent();
auto objectTy = getObjectType(baseTy);
auto loc = origComponent.getLoc();
component = KeyPathExpr::Component::forOptionalForce(objectTy, loc);
Expand Down Expand Up @@ -4461,6 +4472,7 @@ namespace {
resolvedComponents.push_back(component);

if (shouldForceUnwrapResult(foundDecl->choice, locator)) {
updateCSWithResolvedComponent();
auto objectTy = getObjectType(baseTy);
auto loc = origComponent.getLoc();
component = KeyPathExpr::Component::forOptionalForce(objectTy, loc);
Expand Down Expand Up @@ -4512,6 +4524,9 @@ namespace {
case KeyPathExpr::Component::Kind::TupleElement:
llvm_unreachable("already resolved");
}

// By now, "baseTy" is the result type of this component.
updateCSWithResolvedComponent();
}

// Wrap a non-optional result if there was chaining involved.
Expand All @@ -4524,6 +4539,7 @@ namespace {
auto component = KeyPathExpr::Component::forOptionalWrap(leafTy);
resolvedComponents.push_back(component);
baseTy = leafTy;
updateCSWithResolvedComponent();
}
E->resolveComponents(cs.getASTContext(), resolvedComponents);

Expand Down
34 changes: 19 additions & 15 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2974,6 +2974,11 @@ namespace {

for (unsigned i : indices(E->getComponents())) {
auto &component = E->getComponents()[i];
auto memberLocator = CS.getConstraintLocator(
locator, ConstraintLocator::PathElement::getKeyPathComponent(i));
auto resultLocator = CS.getConstraintLocator(
memberLocator, ConstraintLocator::KeyPathComponentResult);

switch (auto kind = component.getKind()) {
case KeyPathExpr::Component::Kind::Invalid:
break;
Expand All @@ -2982,7 +2987,7 @@ namespace {
// This should only appear in resolved ASTs, but we may need to
// re-type-check the constraints during failure diagnosis.
case KeyPathExpr::Component::Kind::Property: {
auto memberTy = CS.createTypeVariable(locator,
auto memberTy = CS.createTypeVariable(resultLocator,
TVO_CanBindToLValue |
TVO_CanBindToNoEscape);
auto lookupName = kind == KeyPathExpr::Component::Kind::UnresolvedProperty
Expand All @@ -2992,8 +2997,6 @@ namespace {
auto refKind = lookupName.isSimpleName()
? FunctionRefKind::Unapplied
: FunctionRefKind::Compound;
auto memberLocator = CS.getConstraintLocator(E,
ConstraintLocator::PathElement::getKeyPathComponent(i));
CS.addValueMemberConstraint(base, lookupName,
memberTy,
CurDC,
Expand All @@ -3008,11 +3011,8 @@ namespace {
// Subscript should only appear in resolved ASTs, but we may need to
// re-type-check the constraints during failure diagnosis.
case KeyPathExpr::Component::Kind::Subscript: {

auto *locator = CS.getConstraintLocator(E,
ConstraintLocator::PathElement::getKeyPathComponent(i));
base = addSubscriptConstraints(E, base, component.getIndexExpr(),
/*decl*/ nullptr, locator);
/*decl*/ nullptr, memberLocator);
break;
}

Expand All @@ -3026,18 +3026,20 @@ namespace {

// We can't assign an optional back through an optional chain
// today. Force the base to an rvalue.
auto rvalueTy = CS.createTypeVariable(locator, TVO_CanBindToNoEscape);
CS.addConstraint(ConstraintKind::Equal, base, rvalueTy, locator);
auto rvalueTy = CS.createTypeVariable(resultLocator,
TVO_CanBindToNoEscape);
CS.addConstraint(ConstraintKind::Equal, base, rvalueTy,
resultLocator);
base = rvalueTy;
LLVM_FALLTHROUGH;
}
case KeyPathExpr::Component::Kind::OptionalForce: {
auto optionalObjTy = CS.createTypeVariable(locator,
auto optionalObjTy = CS.createTypeVariable(resultLocator,
TVO_CanBindToLValue |
TVO_CanBindToNoEscape);

CS.addConstraint(ConstraintKind::OptionalObject, base, optionalObjTy,
locator);
resultLocator);

base = optionalObjTy;
break;
Expand All @@ -3052,6 +3054,10 @@ namespace {
case KeyPathExpr::Component::Kind::Identity:
continue;
}

// By now, `base` is the result type of this component. Set it in the
// constraint system so we can find it later.
CS.setType(E, i, base);
}

// If there was an optional chaining component, the end result must be
Expand All @@ -3078,10 +3084,8 @@ namespace {
} else {
// The type of key path depends on the overloads chosen for the key
// path components.
kpTy = CS.createTypeVariable(CS.getConstraintLocator(E),
TVO_CanBindToNoEscape);
CS.addKeyPathConstraint(kpTy, root, rvalueBase,
CS.getConstraintLocator(E));
kpTy = CS.createTypeVariable(locator, TVO_CanBindToNoEscape);
CS.addKeyPathConstraint(kpTy, root, rvalueBase, locator);
}
return kpTy;
}
Expand Down
14 changes: 1 addition & 13 deletions lib/Sema/CSSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1147,21 +1147,9 @@ ConstraintSystem::solveImpl(Expr *&expr,
}

if (TC.getLangOpts().DebugConstraintSolver) {
auto getTypeOfExpr = [&](const Expr *E) -> Type {
if (hasType(E))
return getType(E);
return Type();
};
auto getTypeOfTypeLoc = [&](const TypeLoc &TL) -> Type {
if (hasType(TL))
return getType(TL);
return Type();
};

auto &log = getASTContext().TypeCheckerDebug->getStream();
log << "---Initial constraints for the given expression---\n";

expr->dump(log, getTypeOfExpr, getTypeOfTypeLoc);
print(log, expr);
log << "\n";
print(log);
}
Expand Down
Loading