Skip to content

Commit 69fdca4

Browse files
committed
Fix assertion failure code completing after nil literal
We were asserting (and doing the wrong thing) when trying to code complete nil #^HERE^# The issue is that we tried to apply a solution to the expression that contained free type variables (converted to generic parameters). This trips us up when we expect the new type to conform to protocols. In code completion we generally only need the type of the expression, so this commit switches to getting that more explicitly. That said, this did cause us to drop non-API parameter names in call patterns after an opening '(' in some cases (covered by rdar://20962472). Thanks to Doug for suggesting this solution! rdar://problem/20891867 Swift SVN r28584
1 parent 5685121 commit 69fdca4

File tree

7 files changed

+176
-50
lines changed

7 files changed

+176
-50
lines changed

include/swift/Sema/CodeCompletionTypeChecking.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,18 @@ namespace swift {
3333
/// \returns true on success, false on error.
3434
bool typeCheckCompletionDecl(Decl *D);
3535

36-
/// \brief Typecheck an expression parsed during code completion.
36+
/// \brief Return the type of an expression parsed during code completion, or
37+
/// None on error.
38+
Optional<Type> getTypeOfCompletionContextExpr(ASTContext &Ctx,
39+
DeclContext *DC,
40+
Expr *&parsedExpr);
41+
42+
/// \brief Typecheck a single parsed expression.
3743
///
3844
/// \returns true on success, false on error.
39-
bool typeCheckCompletionContextExpr(ASTContext &Ctx, DeclContext *DC,
40-
Expr *&parsedExpr);
45+
// FIXME: this is not used by code completion; we should probably move it.
46+
bool typeCheckContextExpr(ASTContext &Ctx, DeclContext *DC,
47+
Expr *&parsedExpr);
4148

4249
/// Partially typecheck the specified function body.
4350
bool typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD,

lib/IDE/CodeCompletion.cpp

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -741,20 +741,18 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
741741
return typeCheckCompletionDecl(DelayedParsedDecl);
742742
}
743743

744-
/// \returns true on success, false on failure.
745-
bool typecheckParsedExpr() {
744+
Optional<Type> getTypeOfParsedExpr() {
746745
assert(ParsedExpr && "should have an expression");
747-
748-
Expr *TypecheckedExpr = ParsedExpr;
749-
if (!typeCheckCompletionContextExpr(P.Context, CurDeclContext,
750-
TypecheckedExpr))
751-
return false;
752-
753-
if (TypecheckedExpr->getType()->is<ErrorType>())
754-
return false;
755-
756-
ParsedExpr = TypecheckedExpr;
757-
return true;
746+
Expr *ModifiedExpr = ParsedExpr;
747+
if (auto T = getTypeOfCompletionContextExpr(P.Context, CurDeclContext,
748+
ModifiedExpr)) {
749+
// FIXME: even though we don't apply the solution, the type checker may
750+
// modify the original expression. We should understand what effect that
751+
// may have on code completion.
752+
ParsedExpr = ModifiedExpr;
753+
return T;
754+
}
755+
return None;
758756
}
759757

760758
/// \returns true on success, false on failure.
@@ -2600,8 +2598,10 @@ void CodeCompletionCallbacksImpl::doneParsing() {
26002598
if (auto *AFD = dyn_cast_or_null<AbstractFunctionDecl>(DelayedParsedDecl))
26012599
CurDeclContext = AFD;
26022600

2603-
if (ParsedExpr && !typecheckParsedExpr()) {
2604-
if (Kind != CompletionKind::PostfixExprParen)
2601+
Optional<Type> ExprType;
2602+
if (ParsedExpr) {
2603+
ExprType = getTypeOfParsedExpr();
2604+
if (!ExprType && Kind != CompletionKind::PostfixExprParen)
26052605
return;
26062606
}
26072607

@@ -2625,7 +2625,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
26252625

26262626
case CompletionKind::DotExpr: {
26272627
Lookup.setHaveDot(DotLoc);
2628-
Type OriginalType = ParsedExpr->getType();
2628+
Type OriginalType = *ExprType;
26292629
Type ExprType = OriginalType;
26302630

26312631
// If there is no nominal type in the expr, try to find nominal types
@@ -2651,10 +2651,9 @@ void CodeCompletionCallbacksImpl::doneParsing() {
26512651
}
26522652

26532653
case CompletionKind::PostfixExpr: {
2654-
Type ExprType = ParsedExpr->getType();
2655-
if (isDynamicLookup(ExprType))
2654+
if (isDynamicLookup(*ExprType))
26562655
Lookup.setIsDynamicLookup();
2657-
Lookup.getValueExprCompletions(ExprType);
2656+
Lookup.getValueExprCompletions(*ExprType);
26582657
break;
26592658
}
26602659

@@ -2665,8 +2664,8 @@ void CodeCompletionCallbacksImpl::doneParsing() {
26652664
if (auto *DRE = dyn_cast<DeclRefExpr>(AE->getFn()))
26662665
VD = DRE->getDecl();
26672666
}
2668-
if (ParsedExpr->getType())
2669-
Lookup.getValueExprCompletions(ParsedExpr->getType(), VD);
2667+
if (ExprType)
2668+
Lookup.getValueExprCompletions(*ExprType, VD);
26702669

26712670
if (!Lookup.FoundFunctionCalls ||
26722671
(Lookup.FoundFunctionCalls &&
@@ -2679,14 +2678,14 @@ void CodeCompletionCallbacksImpl::doneParsing() {
26792678

26802679
case CompletionKind::SuperExpr: {
26812680
Lookup.setIsSuperRefExpr();
2682-
Lookup.getValueExprCompletions(ParsedExpr->getType());
2681+
Lookup.getValueExprCompletions(*ExprType);
26832682
break;
26842683
}
26852684

26862685
case CompletionKind::SuperExprDot: {
26872686
Lookup.setIsSuperRefExpr();
26882687
Lookup.setHaveDot(SourceLoc());
2689-
Lookup.getValueExprCompletions(ParsedExpr->getType());
2688+
Lookup.getValueExprCompletions(*ExprType);
26902689
break;
26912690
}
26922691

lib/Sema/PlaygroundTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ class Instrumenter {
818818
Expr *SendDataCall = new (Context) CallExpr(SendDataRef, SendDataArgs, true,
819819
Type());
820820

821-
if (!typeCheckCompletionContextExpr(Context, TypeCheckDC, SendDataCall)) {
821+
if (!typeCheckContextExpr(Context, TypeCheckDC, SendDataCall)) {
822822
return nullptr;
823823
}
824824

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -860,29 +860,21 @@ static void diagnoseExpr(TypeChecker &TC, const Expr *E,
860860
performExprDiagnostics(TC, E, DC);
861861
}
862862

863-
#pragma mark High-level entry points
864-
bool TypeChecker::typeCheckExpression(
865-
Expr *&expr, DeclContext *dc,
866-
Type convertType,
867-
Type contextualType,
868-
bool discardedExpr,
869-
FreeTypeVariableBinding allowFreeTypeVariables,
870-
ExprTypeCheckListener *listener) {
871-
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
863+
bool TypeChecker::solveForExpression(
864+
Expr *&expr, DeclContext *dc, Type convertType, Type contextualType,
865+
bool discardedExpr, FreeTypeVariableBinding allowFreeTypeVariables,
866+
ExprTypeCheckListener *listener, ConstraintSystem &cs,
867+
SmallVectorImpl<Solution> &viable) {
872868

873869
// First, pre-check the expression, validating any types that occur in the
874870
// expression and folding sequence expressions.
875871
if (preCheckExpression(*this, expr, dc))
876872
return true;
877873

878-
// Construct a constraint system from this expression.
879-
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes);
880-
881874
if (!contextualType.isNull()) {
882875
cs.setContextualType(expr, &contextualType);
883876
}
884-
885-
CleanupIllFormedExpressionRAII cleanup(cs, expr);
877+
886878
if (auto generatedExpr = cs.generateConstraints(expr))
887879
expr = generatedExpr;
888880
else {
@@ -911,7 +903,6 @@ bool TypeChecker::typeCheckExpression(
911903
}
912904

913905
// Attempt to solve the constraint system.
914-
SmallVector<Solution, 4> viable;
915906
if (cs.solve(viable, allowFreeTypeVariables)) {
916907
if (listener && listener->suppressDiagnostics())
917908
return true;
@@ -937,7 +928,31 @@ bool TypeChecker::typeCheckExpression(
937928
listener->solvedConstraints(solution);
938929
}
939930

931+
return false;
932+
}
933+
934+
#pragma mark High-level entry points
935+
bool TypeChecker::typeCheckExpression(
936+
Expr *&expr, DeclContext *dc,
937+
Type convertType,
938+
Type contextualType,
939+
bool discardedExpr,
940+
FreeTypeVariableBinding allowFreeTypeVariables,
941+
ExprTypeCheckListener *listener) {
942+
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
943+
944+
// Construct a constraint system from this expression.
945+
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes);
946+
CleanupIllFormedExpressionRAII cleanup(cs, expr);
947+
948+
// Attempt to solve the constraint system.
949+
SmallVector<Solution, 4> viable;
950+
if (solveForExpression(expr, dc, convertType, contextualType, discardedExpr,
951+
allowFreeTypeVariables, listener, cs, viable))
952+
return true;
953+
940954
// Apply the solution to the expression.
955+
auto &solution = viable[0];
941956
auto result = cs.applySolution(solution, expr, convertType, discardedExpr,
942957
listener && listener->suppressDiagnostics());
943958
if (!result) {
@@ -968,6 +983,33 @@ bool TypeChecker::typeCheckExpression(
968983
return false;
969984
}
970985

986+
Optional<Type> TypeChecker::getTypeOfExpressionWithoutApplying(
987+
Expr *&expr, DeclContext *dc, Type convertType, Type contextualType,
988+
bool discardedExpr, FreeTypeVariableBinding allowFreeTypeVariables,
989+
ExprTypeCheckListener *listener) {
990+
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
991+
992+
// Construct a constraint system from this expression.
993+
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes);
994+
CleanupIllFormedExpressionRAII cleanup(cs, expr);
995+
996+
// Attempt to solve the constraint system.
997+
SmallVector<Solution, 4> viable;
998+
if (solveForExpression(expr, dc, convertType, contextualType, discardedExpr,
999+
allowFreeTypeVariables, listener, cs, viable))
1000+
return None;
1001+
1002+
// Get the expression's simplified type.
1003+
auto &solution = viable[0];
1004+
Type exprType = solution.simplifyType(*this, expr->getType());
1005+
1006+
assert(exprType && !exprType->is<ErrorType>() && "erroneous solution?");
1007+
assert(!exprType->hasTypeVariable() &&
1008+
"free type variable with FreeTypeVariableBinding::GenericParameters?");
1009+
1010+
return exprType;
1011+
}
1012+
9711013
/// Private class to "cleanse" an expression tree of types. This is done in the
9721014
/// case of a typecheck failure, where we may want to re-typecheck partially-
9731015
/// typechecked subexpressions in a context-free manner.

lib/Sema/TypeChecker.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,8 +674,31 @@ bool swift::typeCheckCompletionDecl(Decl *D) {
674674
return true;
675675
}
676676

677-
bool swift::typeCheckCompletionContextExpr(ASTContext &Ctx, DeclContext *DC,
678-
Expr *&parsedExpr) {
677+
/// \brief Return the type of an expression parsed during code completion, or
678+
/// a null \c Type on error.
679+
Optional<Type> swift::getTypeOfCompletionContextExpr(ASTContext &Ctx,
680+
DeclContext *DC,
681+
Expr *&parsedExpr) {
682+
// Set up a diagnostics engine that swallows diagnostics.
683+
DiagnosticEngine diags(Ctx.SourceMgr);
684+
685+
TypeChecker TC(Ctx, diags);
686+
// Try to solve for the actual type of the expression.
687+
if (auto T = TC.getTypeOfExpressionWithoutApplying(
688+
parsedExpr, DC, Type(), Type(), /*discardedExpr=*/true,
689+
FreeTypeVariableBinding::GenericParameters))
690+
return T;
691+
692+
// Try to recover by using the original unchecked type.
693+
if (parsedExpr && !isa<ErrorExpr>(parsedExpr) && parsedExpr->getType() &&
694+
!parsedExpr->getType()->is<ErrorType>())
695+
return parsedExpr->getType();
696+
697+
return None;
698+
}
699+
700+
bool swift::typeCheckContextExpr(ASTContext &Ctx, DeclContext *DC,
701+
Expr *&parsedExpr) {
679702
// Set up a diagnostics engine that swallows diagnostics.
680703
DiagnosticEngine diags(Ctx.SourceMgr);
681704

lib/Sema/TypeChecker.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,19 @@ class TypeChecker final : public LazyResolver {
869869
/// which must be lazy.
870870
void completeLazyVarImplementation(VarDecl *lazyVar);
871871

872+
/// Sets up and solves the constraint system \p cs to type check the given
873+
/// expression.
874+
///
875+
/// \returns true if an error occurred, false otherwise.
876+
///
877+
/// \see typeCheckExpression
878+
bool solveForExpression(Expr *&expr, DeclContext *dc, Type convertType,
879+
Type contextualType, bool discardedExpr,
880+
FreeTypeVariableBinding allowFreeTypeVariables,
881+
ExprTypeCheckListener *listener,
882+
constraints::ConstraintSystem &cs,
883+
SmallVectorImpl<constraints::Solution> &viable);
884+
872885
/// \name Name lookup
873886
///
874887
/// Routines that perform name lookup.
@@ -881,7 +894,7 @@ class TypeChecker final : public LazyResolver {
881894
/// @{
882895
private:
883896
Optional<Type> boolType;
884-
897+
885898
public:
886899
/// \brief Define the default constructor for the given struct or class.
887900
void defineDefaultConstructor(NominalTypeDecl *decl);
@@ -922,6 +935,37 @@ class TypeChecker final : public LazyResolver {
922935
= FreeTypeVariableBinding::Disallow,
923936
ExprTypeCheckListener *listener = nullptr);
924937

938+
/// \brief Type check the given expression and return its type without
939+
/// applying the solution.
940+
///
941+
/// \param expr The expression to type-check.
942+
///
943+
/// \param convertType The type that the expression is being converted to,
944+
/// or null if the expression is standalone.
945+
///
946+
/// \param contextualType Contextual type information that can be applied to
947+
/// the expression. (This is distinct from convertType in that while it can
948+
/// inform the type of the expression, it won't result in a conversion
949+
/// constraint being applied to the expression.)
950+
///
951+
/// \param discardedExpr True if the result of this expression will be
952+
/// discarded.
953+
///
954+
/// \param allowFreeTypeVariables Whether free type variables are allowed in
955+
/// the solution, and what to do with them.
956+
///
957+
/// \param listener If non-null, a listener that will be notified of important
958+
/// events in the type checking of this expression, and which can introduce
959+
/// additional constraints.
960+
///
961+
/// \returns the type of \p expr on success, None otherwise.
962+
/// FIXME: expr may still be modified...
963+
Optional<Type> getTypeOfExpressionWithoutApplying(
964+
Expr *&expr, DeclContext *dc, Type convertType, Type contextualType,
965+
bool discardedExpr, FreeTypeVariableBinding allowFreeTypeVariables =
966+
FreeTypeVariableBinding::Disallow,
967+
ExprTypeCheckListener *listener = nullptr);
968+
925969
/// \brief Type check the given expression assuming that its children
926970
/// have already been fully type-checked.
927971
///

0 commit comments

Comments
 (0)