mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
846 lines
25 KiB
C++
846 lines
25 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 "swift/Sema/ConstraintLocator.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/Expr.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/Sema/Constraint.h"
|
|
#include "swift/Sema/ConstraintLocator.h"
|
|
#include "swift/Sema/ConstraintSystem.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace swift;
|
|
using namespace constraints;
|
|
|
|
void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, ASTNode anchor,
|
|
ArrayRef<PathElement> path) {
|
|
id.AddPointer(anchor.getOpaqueValue());
|
|
id.AddInteger(path.size());
|
|
for (auto elt : path) {
|
|
id.AddInteger(elt.getKind());
|
|
id.AddInteger(elt.getRawStorage());
|
|
}
|
|
}
|
|
|
|
unsigned LocatorPathElt::getNewSummaryFlags() const {
|
|
switch (getKind()) {
|
|
case ConstraintLocator::ApplyArgument:
|
|
case ConstraintLocator::ApplyFunction:
|
|
case ConstraintLocator::SequenceElementType:
|
|
case ConstraintLocator::ClosureResult:
|
|
case ConstraintLocator::ClosureThrownError:
|
|
case ConstraintLocator::ClosureBody:
|
|
case ConstraintLocator::ConstructorMember:
|
|
case ConstraintLocator::ConstructorMemberType:
|
|
case ConstraintLocator::ResultBuilderBodyResult:
|
|
case ConstraintLocator::InstanceType:
|
|
case ConstraintLocator::AutoclosureResult:
|
|
case ConstraintLocator::OptionalInjection:
|
|
case ConstraintLocator::Member:
|
|
case ConstraintLocator::MemberRefBase:
|
|
case ConstraintLocator::UnresolvedMember:
|
|
case ConstraintLocator::ParentType:
|
|
case ConstraintLocator::ExistentialConstraintType:
|
|
case ConstraintLocator::ProtocolCompositionMemberType:
|
|
case ConstraintLocator::LValueConversion:
|
|
case ConstraintLocator::DynamicType:
|
|
case ConstraintLocator::SubscriptMember:
|
|
case ConstraintLocator::OpenedGeneric:
|
|
case ConstraintLocator::OpenedOpaqueArchetype:
|
|
case ConstraintLocator::WrappedValue:
|
|
case ConstraintLocator::GenericParameter:
|
|
case ConstraintLocator::GenericArgument:
|
|
case ConstraintLocator::TupleType:
|
|
case ConstraintLocator::GenericType:
|
|
case ConstraintLocator::NamedTupleElement:
|
|
case ConstraintLocator::TupleElement:
|
|
case ConstraintLocator::ProtocolRequirement:
|
|
case ConstraintLocator::Witness:
|
|
case ConstraintLocator::KeyPathComponent:
|
|
case ConstraintLocator::ConditionalRequirement:
|
|
case ConstraintLocator::TypeParameterRequirement:
|
|
case ConstraintLocator::ConformanceRequirement:
|
|
case ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice:
|
|
case ConstraintLocator::DynamicLookupResult:
|
|
case ConstraintLocator::ContextualType:
|
|
case ConstraintLocator::SynthesizedArgument:
|
|
case ConstraintLocator::KeyPathDynamicMember:
|
|
case ConstraintLocator::KeyPathType:
|
|
case ConstraintLocator::KeyPathRoot:
|
|
case ConstraintLocator::KeyPathValue:
|
|
case ConstraintLocator::KeyPathComponentResult:
|
|
case ConstraintLocator::Condition:
|
|
case ConstraintLocator::DynamicCallable:
|
|
case ConstraintLocator::ImplicitCallAsFunction:
|
|
case ConstraintLocator::TernaryBranch:
|
|
case ConstraintLocator::PatternMatch:
|
|
case ConstraintLocator::EnumPatternImplicitCastMatch:
|
|
case ConstraintLocator::ArgumentAttribute:
|
|
case ConstraintLocator::UnresolvedMemberChainResult:
|
|
case ConstraintLocator::PlaceholderType:
|
|
case ConstraintLocator::ImplicitConversion:
|
|
case ConstraintLocator::ImplicitDynamicMemberSubscript:
|
|
case ConstraintLocator::SyntacticElement:
|
|
case ConstraintLocator::PackType:
|
|
case ConstraintLocator::PackElement:
|
|
case ConstraintLocator::PackShape:
|
|
case ConstraintLocator::PackExpansionPattern:
|
|
case ConstraintLocator::PatternBindingElement:
|
|
case ConstraintLocator::NamedPatternDecl:
|
|
case ConstraintLocator::SingleValueStmtResult:
|
|
case ConstraintLocator::AnyPatternDecl:
|
|
case ConstraintLocator::GlobalActorType:
|
|
case ConstraintLocator::CoercionOperand:
|
|
case ConstraintLocator::PackExpansionType:
|
|
case ConstraintLocator::ThrownErrorType:
|
|
case ConstraintLocator::FallbackType:
|
|
case ConstraintLocator::KeyPathSubscriptIndex:
|
|
case ConstraintLocator::ExistentialMemberAccessConversion:
|
|
return 0;
|
|
|
|
case ConstraintLocator::FunctionArgument:
|
|
case ConstraintLocator::FunctionResult:
|
|
return IsFunctionConversion;
|
|
|
|
case ConstraintLocator::ApplyArgToParam: {
|
|
auto flags = castTo<LocatorPathElt::ApplyArgToParam>().getParameterFlags();
|
|
return flags.isNonEphemeral() ? IsNonEphemeralParam : 0;
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Unhandled PathElementKind in switch.");
|
|
}
|
|
|
|
void LocatorPathElt::dump(raw_ostream &out) const {
|
|
PrintOptions PO = PrintOptions::forDebugging();
|
|
|
|
auto dumpReqKind = [&out](RequirementKind kind) {
|
|
out << " (";
|
|
switch (kind) {
|
|
case RequirementKind::SameShape:
|
|
out << "same_shape";
|
|
break;
|
|
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 << ")";
|
|
};
|
|
|
|
|
|
const LocatorPathElt &elt = *this;
|
|
switch (getKind()) {
|
|
case ConstraintLocator::GenericParameter: {
|
|
auto gpElt = elt.castTo<LocatorPathElt::GenericParameter>();
|
|
out << "generic parameter '" << gpElt.getType()->getString(PO) << "'";
|
|
break;
|
|
}
|
|
case ConstraintLocator::WrappedValue: {
|
|
auto wrappedValueElt = elt.castTo<LocatorPathElt::WrappedValue>();
|
|
out << "composed property wrapper type '"
|
|
<< wrappedValueElt.getType()->getString(PO) << "'";
|
|
break;
|
|
}
|
|
case ConstraintLocator::ApplyArgument:
|
|
out << "apply argument";
|
|
break;
|
|
|
|
case ConstraintLocator::ApplyFunction:
|
|
out << "apply function";
|
|
break;
|
|
|
|
case ConstraintLocator::OptionalInjection:
|
|
out << "optional injection";
|
|
break;
|
|
|
|
case ConstraintLocator::ApplyArgToParam: {
|
|
auto argElt = elt.castTo<LocatorPathElt::ApplyArgToParam>();
|
|
out << "comparing call argument #" << llvm::utostr(argElt.getArgIdx())
|
|
<< " to parameter #" << llvm::utostr(argElt.getParamIdx());
|
|
if (argElt.getParameterFlags().isNonEphemeral())
|
|
out << " (non-ephemeral)";
|
|
break;
|
|
}
|
|
case ConstraintLocator::ClosureResult:
|
|
out << "closure result";
|
|
break;
|
|
|
|
case ConstraintLocator::ClosureThrownError:
|
|
out << "closure thrown error";
|
|
break;
|
|
|
|
case ConstraintLocator::ClosureBody:
|
|
out << "type of a closure body";
|
|
break;
|
|
|
|
case ConstraintLocator::ConstructorMember:
|
|
out << "constructor member";
|
|
break;
|
|
|
|
case ConstraintLocator::ConstructorMemberType: {
|
|
auto memberTypeElt = elt.castTo<LocatorPathElt::ConstructorMemberType>();
|
|
out << "constructor member type";
|
|
if (memberTypeElt.isShortFormOrSelfDelegatingConstructor())
|
|
out << " (for short-form or self.init call)";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::FunctionArgument:
|
|
out << "function argument";
|
|
break;
|
|
|
|
case ConstraintLocator::FunctionResult:
|
|
out << "function result";
|
|
break;
|
|
|
|
case ConstraintLocator::ResultBuilderBodyResult:
|
|
out << "result builder body result";
|
|
break;
|
|
|
|
case ConstraintLocator::SequenceElementType:
|
|
out << "sequence element type";
|
|
break;
|
|
|
|
case ConstraintLocator::GenericArgument: {
|
|
auto genericElt = elt.castTo<LocatorPathElt::GenericArgument>();
|
|
out << "generic argument #" << llvm::utostr(genericElt.getIndex());
|
|
break;
|
|
}
|
|
case ConstraintLocator::InstanceType:
|
|
out << "instance type";
|
|
break;
|
|
|
|
case ConstraintLocator::AutoclosureResult:
|
|
out << "@autoclosure result";
|
|
break;
|
|
|
|
case ConstraintLocator::Member:
|
|
out << "member";
|
|
break;
|
|
|
|
case ConstraintLocator::MemberRefBase:
|
|
out << "member reference base";
|
|
break;
|
|
|
|
case ConstraintLocator::TupleType: {
|
|
auto tupleElt = elt.castTo<LocatorPathElt::TupleType>();
|
|
out << "tuple type '" << tupleElt.getType()->getString(PO) << "'";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::GenericType: {
|
|
auto genericTyElt = elt.castTo<LocatorPathElt::GenericType>();
|
|
out << "generic type '" << genericTyElt.getType()->getString(PO) << "'";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::NamedTupleElement: {
|
|
auto tupleElt = elt.castTo<LocatorPathElt::NamedTupleElement>();
|
|
out << "named tuple element #" << llvm::utostr(tupleElt.getIndex());
|
|
break;
|
|
}
|
|
case ConstraintLocator::UnresolvedMember:
|
|
out << "unresolved member";
|
|
break;
|
|
|
|
case ConstraintLocator::ParentType:
|
|
out << "parent type";
|
|
break;
|
|
|
|
case ConstraintLocator::ExistentialConstraintType:
|
|
out << "existential constraint type";
|
|
break;
|
|
|
|
case ConstraintLocator::ProtocolCompositionMemberType: {
|
|
auto memberElt = elt.castTo<LocatorPathElt::ProtocolCompositionMemberType>();
|
|
out << "protocol composition member " << llvm::utostr(memberElt.getIndex());
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::LValueConversion:
|
|
out << "@lvalue-to-inout conversion";
|
|
break;
|
|
|
|
case ConstraintLocator::DynamicType:
|
|
out << "`.dynamicType` reference";
|
|
break;
|
|
|
|
case ConstraintLocator::SubscriptMember:
|
|
out << "subscript member";
|
|
break;
|
|
|
|
case ConstraintLocator::TupleElement: {
|
|
auto tupleElt = elt.castTo<LocatorPathElt::TupleElement>();
|
|
out << "tuple element #" << llvm::utostr(tupleElt.getIndex());
|
|
break;
|
|
}
|
|
case ConstraintLocator::KeyPathComponent: {
|
|
auto kpElt = elt.castTo<LocatorPathElt::KeyPathComponent>();
|
|
out << "key path component #" << llvm::utostr(kpElt.getIndex());
|
|
break;
|
|
}
|
|
case ConstraintLocator::ProtocolRequirement: {
|
|
out << "protocol requirement";
|
|
break;
|
|
}
|
|
case ConstraintLocator::Witness: {
|
|
auto witnessElt = elt.castTo<LocatorPathElt::Witness>();
|
|
out << "witness ";
|
|
witnessElt.getDecl()->dumpRef(out);
|
|
break;
|
|
}
|
|
case ConstraintLocator::OpenedGeneric:
|
|
out << "opened generic";
|
|
break;
|
|
|
|
case ConstraintLocator::OpenedOpaqueArchetype:
|
|
out << "opened opaque archetype";
|
|
break;
|
|
|
|
case ConstraintLocator::ConditionalRequirement: {
|
|
auto reqElt = elt.castTo<LocatorPathElt::ConditionalRequirement>();
|
|
out << "conditional requirement #" << llvm::utostr(reqElt.getIndex());
|
|
dumpReqKind(reqElt.getRequirementKind());
|
|
break;
|
|
}
|
|
case ConstraintLocator::TypeParameterRequirement: {
|
|
auto reqElt = elt.castTo<LocatorPathElt::TypeParameterRequirement>();
|
|
out << "type parameter requirement #" << llvm::utostr(reqElt.getIndex());
|
|
dumpReqKind(reqElt.getRequirementKind());
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::ConformanceRequirement: {
|
|
auto *conformance =
|
|
elt.castTo<LocatorPathElt::ConformanceRequirement>().getConformance();
|
|
out << "conformance requirement (";
|
|
conformance->getProtocol()->dumpRef(out);
|
|
out << ")";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice:
|
|
out << "implicitly unwrapped disjunction choice";
|
|
break;
|
|
|
|
case ConstraintLocator::DynamicLookupResult:
|
|
out << "dynamic lookup result";
|
|
break;
|
|
|
|
case ConstraintLocator::ContextualType:
|
|
out << "contextual type";
|
|
break;
|
|
|
|
case ConstraintLocator::SynthesizedArgument: {
|
|
auto argElt = elt.castTo<LocatorPathElt::SynthesizedArgument>();
|
|
out << "synthesized argument #" << llvm::utostr(argElt.getIndex());
|
|
break;
|
|
}
|
|
case ConstraintLocator::KeyPathDynamicMember:
|
|
out << "key path dynamic member lookup";
|
|
break;
|
|
|
|
case ConstraintLocator::KeyPathType:
|
|
out << "key path type";
|
|
break;
|
|
|
|
case ConstraintLocator::KeyPathRoot:
|
|
out << "key path root";
|
|
break;
|
|
|
|
case ConstraintLocator::KeyPathValue:
|
|
out << "key path value";
|
|
break;
|
|
|
|
case ConstraintLocator::KeyPathComponentResult:
|
|
out << "key path component result";
|
|
break;
|
|
|
|
case ConstraintLocator::Condition:
|
|
out << "condition expression";
|
|
break;
|
|
|
|
case ConstraintLocator::DynamicCallable:
|
|
out << "implicit call to @dynamicCallable method";
|
|
break;
|
|
|
|
case ConstraintLocator::ImplicitCallAsFunction:
|
|
out << "implicit reference to callAsFunction";
|
|
break;
|
|
|
|
case ConstraintLocator::TernaryBranch: {
|
|
auto branchElt = elt.castTo<LocatorPathElt::TernaryBranch>();
|
|
out << (branchElt.forThen() ? "'then'" : "'else'")
|
|
<< " branch of a ternary operator";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::SingleValueStmtResult: {
|
|
auto branch = elt.castTo<LocatorPathElt::SingleValueStmtResult>();
|
|
out << "result [" << branch.getIndex() << "] of "
|
|
"single value stmt";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::PatternMatch:
|
|
out << "pattern match";
|
|
break;
|
|
|
|
case ConstraintLocator::EnumPatternImplicitCastMatch:
|
|
out << "enum pattern implicit cast match";
|
|
break;
|
|
|
|
case ConstraintLocator::ArgumentAttribute: {
|
|
using AttrLoc = LocatorPathElt::ArgumentAttribute;
|
|
|
|
auto attrElt = elt.castTo<AttrLoc>();
|
|
out << "argument attribute: ";
|
|
|
|
switch (attrElt.getAttr()) {
|
|
case AttrLoc::Attribute::InOut:
|
|
out << "inout";
|
|
break;
|
|
|
|
case AttrLoc::Attribute::Escaping:
|
|
out << "@escaping";
|
|
break;
|
|
|
|
case AttrLoc::Attribute::Concurrent:
|
|
out << "@Sendable";
|
|
break;
|
|
|
|
case AttrLoc::Attribute::GlobalActor:
|
|
out << "@<global actor>";
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::UnresolvedMemberChainResult:
|
|
out << "unresolved chain result";
|
|
break;
|
|
|
|
case ConstraintLocator::PlaceholderType:
|
|
out << "placeholder type";
|
|
break;
|
|
|
|
case ConstraintLocator::ConstraintLocator::SyntacticElement:
|
|
// TODO: Would be great to print a kind of element this is e.g.
|
|
// "if", "for each", "switch" etc.
|
|
out << "syntactic element";
|
|
break;
|
|
|
|
case ConstraintLocator::ConstraintLocator::ImplicitDynamicMemberSubscript:
|
|
out << "implicit dynamic member subscript";
|
|
break;
|
|
|
|
case ConstraintLocator::ConstraintLocator::ImplicitConversion: {
|
|
auto convElt = elt.castTo<LocatorPathElt::ImplicitConversion>();
|
|
out << "implicit conversion " << getName(convElt.getConversionKind());
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::ConstraintLocator::PackType: {
|
|
auto packElt = elt.castTo<LocatorPathElt::PackType>();
|
|
out << "pack type '" << packElt.getType()->getString(PO) << "'";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::PackElement: {
|
|
auto packElt = elt.castTo<LocatorPathElt::PackElement>();
|
|
out << "pack element #" << llvm::utostr(packElt.getIndex());
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::PackShape: {
|
|
out << "pack shape";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::PackExpansionPattern: {
|
|
out << "pack expansion pattern";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::PatternBindingElement: {
|
|
auto patternBindingElt =
|
|
elt.castTo<LocatorPathElt::PatternBindingElement>();
|
|
out << "pattern binding element #"
|
|
<< llvm::utostr(patternBindingElt.getIndex());
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::NamedPatternDecl: {
|
|
out << "named pattern decl";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::AnyPatternDecl: {
|
|
out << "'_' pattern decl";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::GlobalActorType: {
|
|
out << "global actor type";
|
|
break;
|
|
}
|
|
|
|
case ConstraintLocator::CoercionOperand: {
|
|
out << "coercion operand";
|
|
break;
|
|
|
|
case ConstraintLocator::PackExpansionType:
|
|
auto expansionElt = elt.castTo<LocatorPathElt::PackExpansionType>();
|
|
out << "pack expansion type ("
|
|
<< expansionElt.getOpenedType()->getString(PO) << ")";
|
|
break;
|
|
}
|
|
case ConstraintLocator::ThrownErrorType: {
|
|
out << "thrown error type";
|
|
break;
|
|
}
|
|
case ConstraintLocator::FallbackType: {
|
|
out << "fallback type";
|
|
break;
|
|
|
|
case ConstraintLocator::KeyPathSubscriptIndex:
|
|
out << "key path subscript index parameter";
|
|
break;
|
|
}
|
|
case ConstraintLocator::ExistentialMemberAccessConversion:
|
|
out << "existential member access conversion";
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// Determine whether given locator points to the subscript reference
|
|
/// e.g. `foo[0]` or `\Foo.[0]`
|
|
bool ConstraintLocator::isSubscriptMemberRef() const {
|
|
auto anchor = getAnchor();
|
|
if (!anchor)
|
|
return false;
|
|
|
|
// Look through dynamic member lookup since for a subscript reference the
|
|
// dynamic member lookup is also a subscript reference.
|
|
auto path = getPath();
|
|
using KPDynamicMemberElt = LocatorPathElt::KeyPathDynamicMember;
|
|
while (!path.empty() && path.back().is<KPDynamicMemberElt>())
|
|
path = path.drop_back();
|
|
|
|
if (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 || !isExpr<KeyPathExpr>(anchor) || path.size() != 1)
|
|
return false;
|
|
return path.back().is<LocatorPathElt::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();
|
|
});
|
|
}
|
|
|
|
static bool hasKeyPathComponent(
|
|
const ConstraintLocator *loc,
|
|
llvm::function_ref<bool(KeyPathExpr::Component::Kind)> predicate) {
|
|
auto *KPE = getAsExpr<KeyPathExpr>(loc->getAnchor());
|
|
if (!KPE)
|
|
return false;
|
|
|
|
return llvm::any_of(loc->getPath(), [&](const LocatorPathElt &elt) {
|
|
auto keyPathElt = elt.getAs<LocatorPathElt::KeyPathComponent>();
|
|
if (!keyPathElt)
|
|
return false;
|
|
|
|
auto &component = KPE->getComponents()[keyPathElt->getIndex()];
|
|
return predicate(component.getKind());
|
|
});
|
|
}
|
|
|
|
bool ConstraintLocator::isKeyPathSubscriptComponent() const {
|
|
return hasKeyPathComponent(this, [](auto kind) {
|
|
return kind == KeyPathExpr::Component::Kind::Subscript ||
|
|
kind == KeyPathExpr::Component::Kind::UnresolvedSubscript;
|
|
});
|
|
}
|
|
|
|
bool ConstraintLocator::isKeyPathMemberComponent() const {
|
|
return hasKeyPathComponent(this, [](auto kind) {
|
|
return kind == KeyPathExpr::Component::Kind::Member ||
|
|
kind == KeyPathExpr::Component::Kind::UnresolvedMember;
|
|
});
|
|
}
|
|
|
|
bool ConstraintLocator::isKeyPathApplyComponent() const {
|
|
return hasKeyPathComponent(this, [](auto kind) {
|
|
return kind == KeyPathExpr::Component::Kind::Apply ||
|
|
kind == KeyPathExpr::Component::Kind::UnresolvedApply;
|
|
});
|
|
}
|
|
|
|
bool ConstraintLocator::isForKeyPathDynamicMemberLookup() const {
|
|
auto path = getPath();
|
|
return !path.empty() && path.back().isKeyPathDynamicMember();
|
|
}
|
|
|
|
bool ConstraintLocator::isInKeyPathComponent() const {
|
|
return llvm::any_of(getPath(), [&](const LocatorPathElt &elt) {
|
|
return elt.isKeyPathComponent();
|
|
});
|
|
}
|
|
|
|
bool ConstraintLocator::isForKeyPathComponentResult() const {
|
|
return isLastElement<LocatorPathElt::KeyPathComponentResult>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForKeyPathComponent() const {
|
|
return isLastElement<LocatorPathElt::KeyPathComponent>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForGenericParameter() const {
|
|
return isLastElement<LocatorPathElt::GenericParameter>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForWrappedValue() const {
|
|
return isLastElement<LocatorPathElt::WrappedValue>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForSequenceElementType() const {
|
|
return isLastElement<LocatorPathElt::SequenceElementType>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForContextualType() const {
|
|
return isLastElement<LocatorPathElt::ContextualType>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForContextualType(ContextualTypePurpose ctp) const {
|
|
auto elt = getLastElementAs<LocatorPathElt::ContextualType>();
|
|
return elt && elt->getPurpose() == ctp;
|
|
}
|
|
|
|
bool ConstraintLocator::isForAssignment() const {
|
|
return directlyAt<AssignExpr>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForCoercion() const {
|
|
return isLastElement<LocatorPathElt::CoercionOperand>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForOptionalTry() const {
|
|
return directlyAt<OptionalTryExpr>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForResultBuilderBodyResult() const {
|
|
return isFirstElement<LocatorPathElt::ResultBuilderBodyResult>();
|
|
}
|
|
|
|
bool ConstraintLocator::isForMacroExpansion() const {
|
|
return directlyAt<MacroExpansionExpr>();
|
|
}
|
|
|
|
static bool isForSingleValueStmtConjunction(ASTNode anchor,
|
|
ArrayRef<LocatorPathElt> path) {
|
|
auto *SVE = getAsExpr<SingleValueStmtExpr>(anchor);
|
|
if (!SVE)
|
|
return false;
|
|
|
|
if (!path.empty()) {
|
|
// Ignore a trailing SyntacticElement path element for the statement.
|
|
if (auto elt = path.back().getAs<LocatorPathElt::SyntacticElement>()) {
|
|
if (elt->getElement() == ASTNode(SVE->getStmt()))
|
|
path = path.drop_back();
|
|
}
|
|
}
|
|
|
|
// Other than the trailing SyntaticElement, we must be at the anchor.
|
|
return path.empty();
|
|
}
|
|
|
|
bool ConstraintLocator::isForSingleValueStmtConjunction() const {
|
|
return ::isForSingleValueStmtConjunction(getAnchor(), getPath());
|
|
}
|
|
|
|
bool ConstraintLocator::isForSingleValueStmtConjunctionOrBrace() const {
|
|
auto *SVE = getAsExpr<SingleValueStmtExpr>(getAnchor());
|
|
if (!SVE)
|
|
return false;
|
|
|
|
auto path = getPath();
|
|
while (!path.empty()) {
|
|
// Ignore a trailing TernaryBranch locator, which is used for if statements.
|
|
if (path.back().is<LocatorPathElt::TernaryBranch>()) {
|
|
path = path.drop_back();
|
|
continue;
|
|
}
|
|
|
|
// Ignore a SyntaticElement path element for a case statement of a switch,
|
|
// or the catch of a do-catch, or the brace of a do-statement.
|
|
if (auto elt = path.back().getAs<LocatorPathElt::SyntacticElement>()) {
|
|
if (elt->getElement().isStmt(StmtKind::Case)) {
|
|
path = path.drop_back();
|
|
break;
|
|
}
|
|
if (elt->getElement().isStmt(StmtKind::Brace) &&
|
|
isa<DoCatchStmt>(SVE->getStmt())) {
|
|
path = path.drop_back();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return ::isForSingleValueStmtConjunction(getAnchor(), path);
|
|
}
|
|
|
|
bool ConstraintLocator::isForSingleValueStmtBranch() const {
|
|
if (!isExpr<SingleValueStmtExpr>(getAnchor()))
|
|
return false;
|
|
|
|
// Ignore a trailing ContextualType path element.
|
|
auto path = getPath();
|
|
if (isLastElement<LocatorPathElt::ContextualType>())
|
|
path = path.drop_back();
|
|
|
|
if (path.empty())
|
|
return false;
|
|
|
|
return path.back().is<LocatorPathElt::SingleValueStmtResult>();
|
|
}
|
|
|
|
NullablePtr<Pattern> ConstraintLocator::getPatternMatch() const {
|
|
auto matchElt = findLast<LocatorPathElt::PatternMatch>();
|
|
if (!matchElt)
|
|
return nullptr;
|
|
|
|
return matchElt->getPattern();
|
|
}
|
|
|
|
bool ConstraintLocator::isForPatternMatch() const {
|
|
return getPatternMatch() != nullptr;
|
|
}
|
|
|
|
bool ConstraintLocator::isMemberRef() const {
|
|
if (isLastElement<LocatorPathElt::Member>()) {
|
|
return true;
|
|
} else if (isLastElement<LocatorPathElt::KeyPathDynamicMember>()) {
|
|
auto path = getPath();
|
|
if (path.size() >= 2 &&
|
|
path[path.size() - 2].is<LocatorPathElt::Member>()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
|
|
// Check whether we have a path that terminates at a generic parameter.
|
|
return isForGenericParameter() ?
|
|
castLastElementTo<LocatorPathElt::GenericParameter>().getType() : nullptr;
|
|
}
|
|
|
|
Type ConstraintLocator::getWrappedValue() const {
|
|
return isForWrappedValue()
|
|
? castLastElementTo<LocatorPathElt::WrappedValue>().getType()
|
|
: Type();
|
|
}
|
|
|
|
void ConstraintLocator::dump(SourceManager *sm) const {
|
|
dump(sm, llvm::errs());
|
|
llvm::errs() << "\n";
|
|
}
|
|
|
|
void ConstraintLocator::dump(ConstraintSystem *CS) const {
|
|
dump(&CS->getASTContext().SourceMgr, llvm::errs());
|
|
llvm::errs() << "\n";
|
|
}
|
|
|
|
|
|
void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
|
|
out << "locator@" << (void*) this << " [";
|
|
|
|
constraints::dumpAnchor(anchor, sm, out);
|
|
|
|
for (auto elt : getPath()) {
|
|
out << " → ";
|
|
elt.dump(out);
|
|
}
|
|
out << ']';
|
|
}
|
|
|
|
|
|
void ConstraintLocatorBuilder::dump(SourceManager *sm) const {
|
|
dump(sm, llvm::errs());
|
|
llvm::errs() << "\n";
|
|
}
|
|
|
|
void ConstraintLocatorBuilder::dump(ConstraintSystem *CS) const {
|
|
dump(&CS->getASTContext().SourceMgr, llvm::errs());
|
|
llvm::errs() << "\n";
|
|
}
|
|
|
|
void ConstraintLocatorBuilder::dump(SourceManager *SM, llvm::raw_ostream &out) const {
|
|
if (auto prev = previous.dyn_cast<ConstraintLocator *>()) {
|
|
prev->dump(SM, out);
|
|
} else if (auto prev = previous.dyn_cast<ConstraintLocatorBuilder *>()) {
|
|
prev->dump(SM, out);
|
|
}
|
|
if (element) {
|
|
out << " → ";
|
|
element->dump(out);
|
|
}
|
|
}
|