Skip to content

Commit b7cea44

Browse files
committed
Sema: Move code completion entry points to TypeCheckCodeCompletion.cpp
1 parent 34cebb4 commit b7cea44

File tree

4 files changed

+361
-305
lines changed

4 files changed

+361
-305
lines changed

lib/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ add_swift_host_library(swiftSema STATIC
4040
TypeCheckAvailability.cpp
4141
TypeCheckCaptures.cpp
4242
TypeCheckCircularity.cpp
43+
TypeCheckCodeCompletion.cpp
4344
TypeCheckConstraints.cpp
4445
TypeCheckDecl.cpp
4546
TypeCheckDeclObjC.cpp

lib/Sema/TypeCheckCodeCompletion.cpp

Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
//===--- TypeCheckCodeCompletion.cpp - Type Checking for Code Completion --===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements various entry points for use by lib/IDE/.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift/Subsystems.h"
18+
#include "ConstraintSystem.h"
19+
#include "TypeChecker.h"
20+
#include "TypeCheckObjC.h"
21+
#include "TypeCheckType.h"
22+
#include "CodeSynthesis.h"
23+
#include "MiscDiagnostics.h"
24+
#include "swift/AST/ASTWalker.h"
25+
#include "swift/AST/ASTVisitor.h"
26+
#include "swift/AST/Attr.h"
27+
#include "swift/AST/DiagnosticSuppression.h"
28+
#include "swift/AST/ExistentialLayout.h"
29+
#include "swift/AST/Identifier.h"
30+
#include "swift/AST/ImportCache.h"
31+
#include "swift/AST/Initializer.h"
32+
#include "swift/AST/ModuleLoader.h"
33+
#include "swift/AST/NameLookup.h"
34+
#include "swift/AST/PrettyStackTrace.h"
35+
#include "swift/AST/ProtocolConformance.h"
36+
#include "swift/AST/SourceFile.h"
37+
#include "swift/AST/Type.h"
38+
#include "swift/AST/TypeCheckRequests.h"
39+
#include "swift/Basic/Statistic.h"
40+
#include "swift/Basic/STLExtras.h"
41+
#include "swift/Basic/Timer.h"
42+
#include "swift/Parse/Lexer.h"
43+
#include "swift/Sema/IDETypeChecking.h"
44+
#include "swift/Strings.h"
45+
#include "llvm/ADT/DenseMap.h"
46+
#include "llvm/ADT/PointerUnion.h"
47+
#include "llvm/ADT/SmallSet.h"
48+
#include "llvm/ADT/SmallString.h"
49+
#include "llvm/ADT/StringSwitch.h"
50+
#include "llvm/ADT/TinyPtrVector.h"
51+
#include "llvm/ADT/Twine.h"
52+
#include <algorithm>
53+
54+
using namespace swift;
55+
using namespace constraints;
56+
57+
Type TypeChecker::
58+
getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
59+
ConcreteDeclRef &referencedDecl,
60+
FreeTypeVariableBinding allowFreeTypeVariables) {
61+
auto &Context = dc->getASTContext();
62+
FrontendStatsTracer StatsTracer(Context.Stats,
63+
"typecheck-expr-no-apply", expr);
64+
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
65+
referencedDecl = nullptr;
66+
67+
// Construct a constraint system from this expression.
68+
ConstraintSystem cs(dc, ConstraintSystemFlags::SuppressDiagnostics);
69+
70+
// Attempt to solve the constraint system.
71+
const Type originalType = expr->getType();
72+
const bool needClearType = originalType && originalType->hasError();
73+
const auto recoverOriginalType = [&] () {
74+
if (needClearType)
75+
expr->setType(originalType);
76+
};
77+
78+
// If the previous checking gives the expr error type, clear the result and
79+
// re-check.
80+
if (needClearType)
81+
expr->setType(Type());
82+
SolutionApplicationTarget target(
83+
expr, dc, CTP_Unused, Type(), /*isDiscarded=*/false);
84+
auto viable = cs.solve(target, allowFreeTypeVariables);
85+
if (!viable) {
86+
recoverOriginalType();
87+
return Type();
88+
}
89+
90+
// Get the expression's simplified type.
91+
expr = target.getAsExpr();
92+
auto &solution = (*viable)[0];
93+
auto &solutionCS = solution.getConstraintSystem();
94+
Type exprType = solution.simplifyType(solutionCS.getType(expr));
95+
96+
assert(exprType && !exprType->hasTypeVariable() &&
97+
"free type variable with FreeTypeVariableBinding::GenericParameters?");
98+
99+
if (exprType->hasError()) {
100+
recoverOriginalType();
101+
return Type();
102+
}
103+
104+
// Dig the declaration out of the solution.
105+
auto semanticExpr = expr->getSemanticsProvidingExpr();
106+
auto topLocator = cs.getConstraintLocator(semanticExpr);
107+
referencedDecl = solution.resolveLocatorToDecl(topLocator);
108+
109+
if (!referencedDecl.getDecl()) {
110+
// Do another check in case we have a curried call from binding a function
111+
// reference to a variable, for example:
112+
//
113+
// class C {
114+
// func instanceFunc(p1: Int, p2: Int) {}
115+
// }
116+
// func t(c: C) {
117+
// C.instanceFunc(c)#^COMPLETE^#
118+
// }
119+
//
120+
// We need to get the referenced function so we can complete the argument
121+
// labels. (Note that the requirement to have labels in the curried call
122+
// seems inconsistent with the removal of labels from function types.
123+
// If this changes the following code could be removed).
124+
if (auto *CE = dyn_cast<CallExpr>(semanticExpr)) {
125+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(CE->getFn())) {
126+
if (isa<TypeExpr>(UDE->getBase())) {
127+
auto udeLocator = cs.getConstraintLocator(UDE);
128+
auto udeRefDecl = solution.resolveLocatorToDecl(udeLocator);
129+
if (auto *FD = dyn_cast_or_null<FuncDecl>(udeRefDecl.getDecl())) {
130+
if (FD->isInstanceMember())
131+
referencedDecl = udeRefDecl;
132+
}
133+
}
134+
}
135+
}
136+
}
137+
138+
// Recover the original type if needed.
139+
recoverOriginalType();
140+
return exprType;
141+
}
142+
143+
static FunctionType *
144+
getTypeOfCompletionOperatorImpl(DeclContext *DC, Expr *expr,
145+
ConcreteDeclRef &referencedDecl) {
146+
auto &Context = DC->getASTContext();
147+
148+
FrontendStatsTracer StatsTracer(Context.Stats,
149+
"typecheck-completion-operator", expr);
150+
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
151+
152+
ConstraintSystemOptions options;
153+
options |= ConstraintSystemFlags::SuppressDiagnostics;
154+
options |= ConstraintSystemFlags::ReusePrecheckedType;
155+
156+
// Construct a constraint system from this expression.
157+
ConstraintSystem CS(DC, options);
158+
expr = CS.generateConstraints(expr, DC);
159+
if (!expr)
160+
return nullptr;
161+
162+
if (CS.isDebugMode()) {
163+
auto &log = llvm::errs();
164+
log << "---Initial constraints for the given expression---\n";
165+
expr->dump(log);
166+
log << "\n";
167+
CS.print(log);
168+
}
169+
170+
// Attempt to solve the constraint system.
171+
SmallVector<Solution, 4> viable;
172+
if (CS.solve(viable, FreeTypeVariableBinding::Disallow))
173+
return nullptr;
174+
175+
auto &solution = viable[0];
176+
if (CS.isDebugMode()) {
177+
auto &log = llvm::errs();
178+
log << "---Solution---\n";
179+
solution.dump(log);
180+
}
181+
182+
// Fill the results.
183+
Expr *opExpr = cast<ApplyExpr>(expr)->getFn();
184+
referencedDecl =
185+
solution.resolveLocatorToDecl(CS.getConstraintLocator(opExpr));
186+
187+
// Return '(ArgType[, ArgType]) -> ResultType' as a function type.
188+
// We don't use the type of the operator expression because we want the types
189+
// of the *arguments* instead of the types of the parameters.
190+
Expr *argsExpr = cast<ApplyExpr>(expr)->getArg();
191+
SmallVector<FunctionType::Param, 2> argTypes;
192+
if (auto *PE = dyn_cast<ParenExpr>(argsExpr)) {
193+
argTypes.emplace_back(solution.simplifyType(CS.getType(PE->getSubExpr())));
194+
} else if (auto *TE = dyn_cast<TupleExpr>(argsExpr)) {
195+
for (auto arg : TE->getElements())
196+
argTypes.emplace_back(solution.simplifyType(CS.getType(arg)));
197+
}
198+
199+
return FunctionType::get(argTypes, solution.simplifyType(CS.getType(expr)));
200+
}
201+
202+
/// Return the type of operator function for specified LHS, or a null
203+
/// \c Type on error.
204+
FunctionType *
205+
TypeChecker::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
206+
Identifier opName, DeclRefKind refKind,
207+
ConcreteDeclRef &referencedDecl) {
208+
209+
// For the infix operator, find the actual LHS from pre-folded LHS.
210+
if (refKind == DeclRefKind::BinaryOperator)
211+
LHS = TypeChecker::findLHS(DC, LHS, opName);
212+
213+
if (!LHS)
214+
return nullptr;
215+
216+
auto LHSTy = LHS->getType();
217+
218+
// FIXME: 'UnresolvedType' still might be typechecked by an operator.
219+
if (!LHSTy || LHSTy->is<UnresolvedType>())
220+
return nullptr;
221+
222+
// Meta types and function types cannot be a operand of operator expressions.
223+
if (LHSTy->is<MetatypeType>() || LHSTy->is<AnyFunctionType>())
224+
return nullptr;
225+
226+
auto Loc = LHS->getEndLoc();
227+
228+
// Build temporary expression to typecheck.
229+
// We allocate these expressions on the stack because we know they can't
230+
// escape and there isn't a better way to allocate scratch Expr nodes.
231+
UnresolvedDeclRefExpr UDRE(DeclNameRef(opName), refKind, DeclNameLoc(Loc));
232+
auto *opExpr = TypeChecker::resolveDeclRefExpr(&UDRE, DC);
233+
234+
switch (refKind) {
235+
236+
case DeclRefKind::PostfixOperator: {
237+
// (postfix_unary_expr
238+
// (declref_expr name=<opName>)
239+
// (paren_expr
240+
// (<LHS>)))
241+
ParenExpr Args(SourceLoc(), LHS, SourceLoc(),
242+
/*hasTrailingClosure=*/false);
243+
PostfixUnaryExpr postfixExpr(opExpr, &Args);
244+
return getTypeOfCompletionOperatorImpl(DC, &postfixExpr,
245+
referencedDecl);
246+
}
247+
248+
case DeclRefKind::BinaryOperator: {
249+
// (binary_expr
250+
// (declref_expr name=<opName>)
251+
// (tuple_expr
252+
// (<LHS>)
253+
// (code_completion_expr)))
254+
CodeCompletionExpr dummyRHS(Loc);
255+
auto Args = TupleExpr::create(
256+
DC->getASTContext(), SourceLoc(), {LHS, &dummyRHS}, {}, {}, SourceLoc(),
257+
/*hasTrailingClosure=*/false, /*isImplicit=*/true);
258+
BinaryExpr binaryExpr(opExpr, Args, /*isImplicit=*/true);
259+
260+
return getTypeOfCompletionOperatorImpl(DC, &binaryExpr,
261+
referencedDecl);
262+
}
263+
264+
default:
265+
llvm_unreachable("Invalid DeclRefKind for operator completion");
266+
}
267+
}
268+
269+
void TypeChecker::typeCheckForCodeCompletion(
270+
Expr *expr, DeclContext *DC, Type contextualType, ContextualTypePurpose CTP,
271+
llvm::function_ref<void(const Solution &)> callback) {
272+
auto &Context = DC->getASTContext();
273+
274+
FrontendStatsTracer StatsTracer(Context.Stats,
275+
"typecheck-for-code-completion", expr);
276+
PrettyStackTraceExpr stackTrace(Context, "code-completion", expr);
277+
278+
ConstraintSystem::solveForCodeCompletion(expr, DC, contextualType, CTP,
279+
callback);
280+
}
281+
282+
static Optional<Type> getTypeOfCompletionContextExpr(
283+
DeclContext *DC,
284+
CompletionTypeCheckKind kind,
285+
Expr *&parsedExpr,
286+
ConcreteDeclRef &referencedDecl) {
287+
if (constraints::ConstraintSystem::preCheckExpression(parsedExpr, DC))
288+
return None;
289+
290+
switch (kind) {
291+
case CompletionTypeCheckKind::Normal:
292+
// Handle below.
293+
break;
294+
295+
case CompletionTypeCheckKind::KeyPath:
296+
referencedDecl = nullptr;
297+
if (auto keyPath = dyn_cast<KeyPathExpr>(parsedExpr))
298+
return TypeChecker::checkObjCKeyPathExpr(DC, keyPath,
299+
/*requireResultType=*/true);
300+
301+
return None;
302+
}
303+
304+
Type originalType = parsedExpr->getType();
305+
if (auto T = TypeChecker::getTypeOfExpressionWithoutApplying(parsedExpr, DC,
306+
referencedDecl, FreeTypeVariableBinding::UnresolvedType))
307+
return T;
308+
309+
// Try to recover if we've made any progress.
310+
if (parsedExpr &&
311+
!isa<ErrorExpr>(parsedExpr) &&
312+
parsedExpr->getType() &&
313+
!parsedExpr->getType()->hasError() &&
314+
(originalType.isNull() ||
315+
!parsedExpr->getType()->isEqual(originalType))) {
316+
return parsedExpr->getType();
317+
}
318+
319+
return None;
320+
}
321+
322+
/// Return the type of an expression parsed during code completion, or
323+
/// a null \c Type on error.
324+
Optional<Type> swift::getTypeOfCompletionContextExpr(
325+
ASTContext &Ctx,
326+
DeclContext *DC,
327+
CompletionTypeCheckKind kind,
328+
Expr *&parsedExpr,
329+
ConcreteDeclRef &referencedDecl) {
330+
DiagnosticSuppression suppression(Ctx.Diags);
331+
332+
// Try to solve for the actual type of the expression.
333+
return ::getTypeOfCompletionContextExpr(DC, kind, parsedExpr,
334+
referencedDecl);
335+
}
336+
337+
/// Return the type of operator function for specified LHS, or a null
338+
/// \c Type on error.
339+
FunctionType *
340+
swift::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
341+
Identifier opName, DeclRefKind refKind,
342+
ConcreteDeclRef &referencedDecl) {
343+
auto &ctx = DC->getASTContext();
344+
DiagnosticSuppression suppression(ctx.Diags);
345+
return TypeChecker::getTypeOfCompletionOperator(DC, LHS, opName, refKind,
346+
referencedDecl);
347+
}
348+
349+
bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) {
350+
auto &ctx = DC->getASTContext();
351+
DiagnosticSuppression suppression(ctx.Diags);
352+
auto resultTy = TypeChecker::typeCheckExpression(parsedExpr, DC, Type(),
353+
CTP_Unused);
354+
return !resultTy;
355+
}
356+
357+
LookupResult
358+
swift::lookupSemanticMember(DeclContext *DC, Type ty, DeclName name) {
359+
return TypeChecker::lookupMember(DC, ty, DeclNameRef(name), None);
360+
}

0 commit comments

Comments
 (0)