Skip to content

WIP: [CodeCompletion] Migrate PostfixExprParen to solver-based #42156

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

Closed
Closed
23 changes: 23 additions & 0 deletions include/swift/AST/ASTNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ namespace swift {

/// Whether the AST node is implicit.
bool isImplicit() const;

static inline ASTNode getFromOpaqueValue(void *VP) {
ASTNode V;
V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
return V;
}

friend llvm::hash_code hash_value(ASTNode N) {
return llvm::hash_value(N.getOpaqueValue());
}
};
} // namespace swift

Expand All @@ -97,6 +107,19 @@ namespace llvm {
return LHS.getOpaqueValue() == RHS.getOpaqueValue();
}
};

// A ASTNode is "pointer like".
template <>
struct PointerLikeTypeTraits<ASTNode> {
public:
static inline void *getAsVoidPointer(ASTNode N) {
return (void *)N.getOpaqueValue();
}
static inline ASTNode getFromVoidPointer(void *P) {
return ASTNode::getFromOpaqueValue(P);
}
enum { NumLowBitsAvailable = swift::TypeAlignInBits };
};
}

#endif // LLVM_SWIFT_AST_AST_NODE_H
73 changes: 71 additions & 2 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "swift/AST/ActorIsolation.h"
#include "swift/AST/AnyFunctionRef.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/ASTTypeIDs.h"
#include "swift/AST/Effects.h"
#include "swift/AST/GenericParamList.h"
Expand Down Expand Up @@ -1544,12 +1545,78 @@ class TypeCheckFunctionBodyRequest
readDependencySource(const evaluator::DependencyRecorder &) const;
};

/// Describes the context in which the AST node to type check in a
/// \c TypeCheckASTNodeAtLocRequest should be searched. This can be either of
/// two cases:
/// 1. A \c DeclContext that contains the node representing the location to
/// type check
/// 2. If the node that should be type checked that might not be part of the
/// AST (e.g. because it is a dangling property attribute), an \c ASTNode
/// that contains the location to type check in together with a DeclContext
/// in which we should pretend that node occurs.
class TypeCheckASTNodeAtLocContext {
DeclContext *DC;
ASTNode Node;

/// Memberwise initializer
TypeCheckASTNodeAtLocContext(DeclContext *DC, ASTNode Node)
: DC(DC), Node(Node) {
assert(DC != nullptr);
}

public:
static TypeCheckASTNodeAtLocContext declContext(DeclContext *DC) {
return TypeCheckASTNodeAtLocContext(DC, /*Node=*/nullptr);
}

static TypeCheckASTNodeAtLocContext node(DeclContext *DC, ASTNode Node) {
assert(!Node.isNull());
return TypeCheckASTNodeAtLocContext(DC, Node);
}

DeclContext *getDeclContext() const { return DC; }

bool isForUnattachedNode() const { return !Node.isNull(); }

ASTNode getUnattachedNode() const {
assert(isForUnattachedNode());
return Node;
}

ASTNode &getUnattachedNode() {
assert(isForUnattachedNode());
return Node;
}

friend llvm::hash_code hash_value(const TypeCheckASTNodeAtLocContext &ctx) {
return llvm::hash_combine(ctx.DC, ctx.Node);
}

friend bool operator==(const TypeCheckASTNodeAtLocContext &lhs,
const TypeCheckASTNodeAtLocContext &rhs) {
return lhs.DC == rhs.DC && lhs.Node == rhs.Node;
}

friend bool operator!=(const TypeCheckASTNodeAtLocContext &lhs,
const TypeCheckASTNodeAtLocContext &rhs) {
return !(lhs == rhs);
}

friend SourceLoc
extractNearestSourceLoc(const TypeCheckASTNodeAtLocContext &ctx) {
return extractNearestSourceLoc(ctx.DC);
}
};

void simple_display(llvm::raw_ostream &out,
const TypeCheckASTNodeAtLocContext &ctx);

/// Request to typecheck a function body element at the given source location.
///
/// Produces true if an error occurred, false otherwise.
class TypeCheckASTNodeAtLocRequest
: public SimpleRequest<TypeCheckASTNodeAtLocRequest,
bool(DeclContext *, SourceLoc),
bool(TypeCheckASTNodeAtLocContext, SourceLoc),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -1558,7 +1625,8 @@ class TypeCheckASTNodeAtLocRequest
friend SimpleRequest;

// Evaluation.
bool evaluate(Evaluator &evaluator, DeclContext *DC, SourceLoc Loc) const;
bool evaluate(Evaluator &evaluator, TypeCheckASTNodeAtLocContext,
SourceLoc Loc) const;
};

/// Request to obtain a list of stored properties in a nominal type.
Expand Down Expand Up @@ -3605,6 +3673,7 @@ class GetSourceFileAsyncNode
bool isCached() const { return true; }
};

void simple_display(llvm::raw_ostream &out, ASTNode node);
void simple_display(llvm::raw_ostream &out, Type value);
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyRequest,
BraceStmt *(AbstractFunctionDecl *), SeparatelyCached,
NoLocationInfo)
SWIFT_REQUEST(TypeChecker, TypeCheckASTNodeAtLocRequest,
bool(DeclContext *, SourceLoc),
bool(TypeCheckASTNodeAtLocContext, SourceLoc),
Uncached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *),
SeparatelyCached, NoLocationInfo)
Expand Down
6 changes: 6 additions & 0 deletions include/swift/IDE/ArgumentCompletion.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
struct Result {
/// The type associated with the code completion expression itself.
Type ExpectedType;
/// The expected return type of the function call.
Type ExpectedCallType;
/// True if this is a subscript rather than a function call.
bool IsSubscript;
/// The FuncDecl or SubscriptDecl associated with the call.
Expand Down Expand Up @@ -70,6 +72,10 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {

void sawSolutionImpl(const constraints::Solution &solution) override;

/// Populates \p OverriddenDecls with all \c FuncD in \p Results that are less
/// specialized as some other \c FuncD in \p Results.
void computeOverriddenDecls(SmallPtrSetImpl<ValueDecl *> &OverriddenDecls);

public:
ArgumentTypeCheckCompletionCallback(CodeCompletionExpr *CompletionExpr,
DeclContext *DC)
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Parse/CodeCompletionCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ class CodeCompletionCallbacks {
/// Set target decl for attribute if the CC token is in attribute of the decl.
virtual void setAttrTargetDeclKind(Optional<DeclKind> DK) {}

/// Set that the code completion token occurred in a custom attribute. This
/// allows us to type check the custom attribute even if it is not attached to
/// the AST, e.g. because there is no var declaration following it.
virtual void setCompletingInAttribute(CustomAttr *Attr){};

/// Complete expr-dot after we have consumed the dot.
virtual void completeDotExpr(CodeCompletionExpr *E, SourceLoc DotLoc) {};

Expand Down
21 changes: 21 additions & 0 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -5186,6 +5186,19 @@ class ConstraintSystem {
/// to a generic function?
bool isArgumentGenericFunction(Type argType, Expr *argExpr);

/// Determine whether given constructor reference is valid or does it require
/// any fixes e.g. when base is a protocol metatype.
/// The function ref parameters can be used to validate an intializer ref with
/// types from a solution during code completion.
ConstraintFix *validateInitializerRef(
ConstructorDecl *init, ConstraintLocator *locator,
llvm::function_ref<Type(ASTNode)> getType,
llvm::function_ref<Type(Type)> simplifyType,
llvm::function_ref<bool(Expr *)> isTypeReference,
llvm::function_ref<bool(Expr *)> isStaticallyDerivedMetatype);
ConstraintFix *validateInitializerRef(ConstructorDecl *init,
ConstraintLocator *locator);

// Given a type variable, attempt to find the disjunction of
// bind overloads associated with it. This may return null in cases where
// the disjunction has either not been created or binds the type variable
Expand Down Expand Up @@ -5820,6 +5833,14 @@ Type getDynamicSelfReplacementType(Type baseObjTy, const ValueDecl *member,

ValueDecl *getOverloadChoiceDecl(Constraint *choice);

/// Determine whether the first declaration is as "specialized" as
/// the second declaration.
///
/// "Specialized" is essentially a form of subtyping, defined by
/// \c CompareDeclSpecializationRequest.
bool isDeclAsSpecializedAs(DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2,
bool isDynamicOverloadComparison = false);

class DisjunctionChoice {
ConstraintSystem &CS;
unsigned Index;
Expand Down
14 changes: 11 additions & 3 deletions include/swift/Sema/IDETypeChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
#ifndef SWIFT_SEMA_IDETYPECHECKING_H
#define SWIFT_SEMA_IDETYPECHECKING_H

#include "swift/AST/ASTNode.h"
#include "swift/AST/Identifier.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Basic/SourceLoc.h"
#include <memory>
#include <tuple>

Expand Down Expand Up @@ -144,8 +146,9 @@ namespace swift {
/// Typecheck the given expression.
bool typeCheckExpression(DeclContext *DC, Expr *&parsedExpr);

/// Type check a function body element which is at \p TagetLoc .
bool typeCheckASTNodeAtLoc(DeclContext *DC, SourceLoc TargetLoc);
/// Type check a function body element which is at \p TagetLoc.
bool typeCheckASTNodeAtLoc(TypeCheckASTNodeAtLocContext TypeCheckCtx,
SourceLoc TargetLoc);

/// Thunk around \c TypeChecker::typeCheckForCodeCompletion to make it
/// available to \c swift::ide.
Expand All @@ -163,6 +166,11 @@ namespace swift {
constraints::SolutionApplicationTarget &target, bool needsPrecheck,
llvm::function_ref<void(const constraints::Solution &)> callback);

/// Thunk around \c TypeChecker::typeCheckASTNode to make it available to
/// \c swift::ide.
void typeCheckASTNode(ASTNode &node, DeclContext *DC,
bool LeaveBodyUnchecked = false);

LookupResult
lookupSemanticMember(DeclContext *DC, Type ty, DeclName name);

Expand Down
8 changes: 8 additions & 0 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ void swift::simple_display(llvm::raw_ostream &out,
}
}

void swift::simple_display(llvm::raw_ostream &out, ASTNode node) {
if (node) {
node.dump(out);
} else {
out << "null";
}
}

void swift::simple_display(llvm::raw_ostream &out, Type type) {
if (type)
type.print(out);
Expand Down
Loading