Files
swift-mirror/lib/Sema/ConstraintLocator.cpp
Hamish Knight a0919f73b0 [CS] Use subclasses to expose locator element info
Instead of adding specific accessors directly to
ConstraintLocator::PathElement, add subclasses that expose these
accessors.
2019-08-19 11:58:49 +01:00

426 lines
11 KiB
C++

//===--- ConstraintLocator.cpp - Constraint Locator -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the \c ConstraintLocator class and its related types,
// which is used by the constraint-based type checker to describe how
// a particular constraint was derived.
//
//===----------------------------------------------------------------------===//
#include "ConstraintLocator.h"
#include "ConstraintSystem.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
using namespace constraints;
void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
ArrayRef<PathElement> path) {
id.AddPointer(anchor);
id.AddInteger(path.size());
for (auto elt : path) {
id.AddInteger(elt.getKind());
switch (elt.getKind()) {
case GenericParameter:
id.AddPointer(elt.castTo<LocatorPathElt::GenericParameter>().getType());
break;
case Requirement:
id.AddPointer(elt.castTo<LocatorPathElt::Requirement>().getDecl());
break;
case Witness:
id.AddPointer(elt.castTo<LocatorPathElt::Witness>().getDecl());
break;
case KeyPathDynamicMember: {
auto kpElt = elt.castTo<LocatorPathElt::KeyPathDynamicMember>();
id.AddPointer(kpElt.getKeyPathDecl());
break;
}
case ApplyArgument:
case ApplyFunction:
case FunctionArgument:
case DefaultArgument:
case FunctionResult:
case OptionalPayload:
case Member:
case MemberRefBase:
case UnresolvedMember:
case SubscriptMember:
case ConstructorMember:
case LValueConversion:
case RValueAdjustment:
case ClosureResult:
case ParentType:
case ExistentialSuperclassType:
case InstanceType:
case SequenceElementType:
case AutoclosureResult:
case GenericArgument:
case NamedTupleElement:
case TupleElement:
case ApplyArgToParam:
case OpenedGeneric:
case KeyPathComponent:
case ConditionalRequirement:
case TypeParameterRequirement:
case ImplicitlyUnwrappedDisjunctionChoice:
case DynamicLookupResult:
case ContextualType:
case SynthesizedArgument:
case KeyPathType:
case KeyPathRoot:
case KeyPathValue:
case KeyPathComponentResult:
auto numValues = numNumericValuesInPathElement(elt.getKind());
for (unsigned i = 0; i < numValues; ++i)
id.AddInteger(elt.getValue(i));
break;
}
}
}
bool LocatorPathElt::isResultOfSingleExprFunction() const {
if (auto elt = getAs<ContextualType>())
return elt->isForSingleExprFunction();
return false;
}
/// Determine whether given locator points to the subscript reference
/// e.g. `foo[0]` or `\Foo.[0]`
bool ConstraintLocator::isSubscriptMemberRef() const {
auto *anchor = getAnchor();
auto path = getPath();
if (!anchor || path.empty())
return false;
return path.back().getKind() == ConstraintLocator::SubscriptMember;
}
bool ConstraintLocator::isKeyPathType() const {
auto *anchor = getAnchor();
auto path = getPath();
// The format of locator should be `<keypath expr> -> key path type`
if (!anchor || !isa<KeyPathExpr>(anchor) || path.size() != 1)
return false;
return path.back().getKind() == ConstraintLocator::KeyPathType;
}
bool ConstraintLocator::isKeyPathRoot() const {
auto *anchor = getAnchor();
auto path = getPath();
if (!anchor || path.empty())
return false;
return path.back().getKind() == ConstraintLocator::KeyPathRoot;
}
bool ConstraintLocator::isKeyPathValue() const {
auto *anchor = getAnchor();
auto path = getPath();
if (!anchor || path.empty())
return false;
return path.back().getKind() == ConstraintLocator::KeyPathValue;
}
bool ConstraintLocator::isResultOfKeyPathDynamicMemberLookup() const {
return llvm::any_of(getPath(), [](const LocatorPathElt &elt) {
return elt.isKeyPathDynamicMember();
});
}
bool ConstraintLocator::isKeyPathSubscriptComponent() const {
auto *anchor = getAnchor();
auto *KPE = dyn_cast_or_null<KeyPathExpr>(anchor);
if (!KPE)
return false;
using ComponentKind = KeyPathExpr::Component::Kind;
return llvm::any_of(getPath(), [&](const LocatorPathElt &elt) {
auto keyPathElt = elt.getAs<LocatorPathElt::KeyPathComponent>();
if (!keyPathElt)
return false;
auto index = keyPathElt->getIndex();
auto &component = KPE->getComponents()[index];
return component.getKind() == ComponentKind::Subscript ||
component.getKind() == ComponentKind::UnresolvedSubscript;
});
}
bool ConstraintLocator::isForKeyPathDynamicMemberLookup() const {
auto path = getPath();
return !path.empty() && path.back().isKeyPathDynamicMember();
}
bool ConstraintLocator::isForKeyPathComponent() const {
return llvm::any_of(getPath(), [&](const LocatorPathElt &elt) {
return elt.isKeyPathComponent();
});
}
bool ConstraintLocator::isLastElement(
ConstraintLocator::PathElementKind expectedKind) const {
auto path = getPath();
return !path.empty() && path.back().getKind() == expectedKind;
}
bool ConstraintLocator::isForGenericParameter() const {
return isLastElement(ConstraintLocator::GenericParameter);
}
bool ConstraintLocator::isForSequenceElementType() const {
return isLastElement(ConstraintLocator::SequenceElementType);
}
bool ConstraintLocator::isForContextualType() const {
return isLastElement(ConstraintLocator::ContextualType);
}
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
auto path = getPath();
assert(!path.empty());
return path.back().castTo<LocatorPathElt::GenericParameter>().getType();
}
void ConstraintLocator::dump(SourceManager *sm) {
dump(sm, llvm::errs());
llvm::errs() << "\n";
}
void ConstraintLocator::dump(ConstraintSystem *CS) {
dump(&CS->TC.Context.SourceMgr, llvm::errs());
llvm::errs() << "\n";
}
void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) {
out << "locator@" << (void*) this << " [";
if (anchor) {
out << Expr::getKindName(anchor->getKind());
if (sm) {
out << '@';
anchor->getLoc().print(out, *sm);
}
}
auto dumpReqKind = [&out](RequirementKind kind) {
out << " (";
switch (kind) {
case RequirementKind::Conformance:
out << "conformance";
break;
case RequirementKind::Superclass:
out << "superclass";
break;
case RequirementKind::SameType:
out << "same-type";
break;
case RequirementKind::Layout:
out << "layout";
break;
}
out << ")";
};
for (auto elt : getPath()) {
out << " -> ";
switch (elt.getKind()) {
case GenericParameter: {
auto gpElt = elt.castTo<LocatorPathElt::GenericParameter>();
out << "generic parameter '" << gpElt.getType()->getString() << "'";
break;
}
case ApplyArgument:
out << "apply argument";
break;
case ApplyFunction:
out << "apply function";
break;
case OptionalPayload:
out << "optional payload";
break;
case ApplyArgToParam: {
auto argElt = elt.castTo<LocatorPathElt::ApplyArgToParam>();
out << "comparing call argument #" << llvm::utostr(argElt.getArgIdx())
<< " to parameter #" << llvm::utostr(argElt.getParamIdx());
break;
}
case ClosureResult:
out << "closure result";
break;
case ConstructorMember:
out << "constructor member";
break;
case FunctionArgument:
out << "function argument";
break;
case DefaultArgument:
out << "default argument";
break;
case FunctionResult:
out << "function result";
break;
case SequenceElementType:
out << "sequence element type";
break;
case GenericArgument: {
auto genericElt = elt.castTo<LocatorPathElt::GenericArgument>();
out << "generic argument #" << llvm::utostr(genericElt.getIndex());
break;
}
case InstanceType:
out << "instance type";
break;
case AutoclosureResult:
out << "@autoclosure result";
break;
case Member:
out << "member";
break;
case MemberRefBase:
out << "member reference base";
break;
case NamedTupleElement: {
auto tupleElt = elt.castTo<LocatorPathElt::NamedTupleElement>();
out << "named tuple element #" << llvm::utostr(tupleElt.getIndex());
break;
}
case UnresolvedMember:
out << "unresolved member";
break;
case ParentType:
out << "parent type";
break;
case ExistentialSuperclassType:
out << "existential superclass type";
break;
case LValueConversion:
out << "@lvalue-to-inout conversion";
break;
case RValueAdjustment:
out << "rvalue adjustment";
break;
case SubscriptMember:
out << "subscript member";
break;
case TupleElement: {
auto tupleElt = elt.castTo<LocatorPathElt::TupleElement>();
out << "tuple element #" << llvm::utostr(tupleElt.getIndex());
break;
}
case KeyPathComponent: {
auto kpElt = elt.castTo<LocatorPathElt::KeyPathComponent>();
out << "key path component #" << llvm::utostr(kpElt.getIndex());
break;
}
case Requirement: {
auto reqElt = elt.castTo<LocatorPathElt::Requirement>();
out << "requirement ";
reqElt.getDecl()->dumpRef(out);
break;
}
case Witness: {
auto witnessElt = elt.castTo<LocatorPathElt::Witness>();
out << "witness ";
witnessElt.getDecl()->dumpRef(out);
break;
}
case OpenedGeneric:
out << "opened generic";
break;
case ConditionalRequirement: {
auto reqElt = elt.castTo<LocatorPathElt::ConditionalRequirement>();
out << "conditional requirement #" << llvm::utostr(reqElt.getIndex());
dumpReqKind(reqElt.getRequirementKind());
break;
}
case TypeParameterRequirement: {
auto reqElt = elt.castTo<LocatorPathElt::TypeParameterRequirement>();
out << "type parameter requirement #" << llvm::utostr(reqElt.getIndex());
dumpReqKind(reqElt.getRequirementKind());
break;
}
case ImplicitlyUnwrappedDisjunctionChoice:
out << "implicitly unwrapped disjunction choice";
break;
case DynamicLookupResult:
out << "dynamic lookup result";
break;
case ContextualType:
if (elt.isResultOfSingleExprFunction())
out << "expected result type of the function with a single expression";
else
out << "contextual type";
break;
case SynthesizedArgument: {
auto argElt = elt.castTo<LocatorPathElt::SynthesizedArgument>();
out << "synthesized argument #" << llvm::utostr(argElt.getIndex());
break;
}
case KeyPathDynamicMember:
out << "key path dynamic member lookup";
break;
case KeyPathType:
out << "key path type";
break;
case KeyPathRoot:
out << "key path root";
break;
case KeyPathValue:
out << "key path value";
break;
case KeyPathComponentResult:
out << "key path component result";
break;
}
}
out << ']';
}