[CS] Remove ConstraintSystem::getVarType

The logic here for completion wasn't actually
helping things since it would result in adding the
var overload to the system, which would result
in an ErrorType binding. We could turn the ErrorType
into a placeholder when resolving the overload,
but the simpler solution is to just allow CSGen
to turn the reference into a PlaceholderType. This
matches what we do for regular solving, and fixes
a crash with an IUO completion.

rdar://89369091
This commit is contained in:
Hamish Knight
2024-11-01 14:06:04 +00:00
parent 43839ac5fd
commit 7061a20edd
6 changed files with 37 additions and 27 deletions

View File

@@ -134,10 +134,10 @@ Type swift::ide::getPatternMatchType(const constraints::Solution &S, Expr *E) {
// not part of the solution.
// TODO: This can be removed once ExprPattern type-checking is fully part
// of the constraint system.
if (auto T = S.getConstraintSystem().getVarType(MatchVar))
return T;
return getTypeForCompletion(S, MatchVar);
auto Ty = MatchVar->getTypeInContext();
if (Ty->hasError())
return Type();
return Ty;
}
void swift::ide::getSolutionSpecificVarTypes(

View File

@@ -1530,7 +1530,7 @@ namespace {
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
knownType = CS.getTypeIfAvailable(VD);
if (!knownType)
knownType = CS.getVarType(VD);
knownType = VD->getTypeInContext();
if (knownType) {
// An out-of-scope type variable(s) could appear the type of
@@ -2420,7 +2420,7 @@ namespace {
Type externalType;
if (param->getTypeRepr()) {
auto declaredTy = CS.getVarType(param);
auto declaredTy = param->getTypeInContext();
// If closure parameter couldn't be resolved, let's record
// a fix to make sure that type resolution diagnosed the
@@ -4899,7 +4899,7 @@ bool ConstraintSystem::generateConstraints(
case SyntacticElementTarget::Kind::uninitializedVar: {
if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
auto propertyType = getVarType(wrappedVar);
auto propertyType = wrappedVar->getTypeInContext();
if (propertyType->hasError())
return true;

View File

@@ -4853,24 +4853,6 @@ void ConstraintSystem::removeFixedRequirement(GenericTypeParamType *GP,
ASSERT(erased);
}
// Replace any error types encountered with placeholders.
Type ConstraintSystem::getVarType(const VarDecl *var) {
auto type = var->getTypeInContext();
// If this declaration is used as part of a code completion
// expression, solver needs to glance over the fact that
// it might be invalid to avoid failing constraint generation
// and produce completion results.
if (!isForCodeCompletion())
return type;
return type.transformRec([&](Type type) -> std::optional<Type> {
if (!type->is<ErrorType>())
return std::nullopt;
return Type(PlaceholderType::get(Context, const_cast<VarDecl *>(var)));
});
}
bool ConstraintSystem::isReadOnlyKeyPathComponent(
const AbstractStorageDecl *storage, SourceLoc referenceLoc) {
// See whether key paths can store to this component. (Key paths don't

View File

@@ -34,6 +34,15 @@ enum FooEnum: CaseIterable {
// FOO_ENUM_DOT-DAG: Decl[TypeAlias]/CurrNominal: AllCases[#[FooEnum]#]{{; name=.+$}}
// FOO_ENUM_DOT-DAG: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}}
// FOO_ENUM_DOT_INVALID-DAG: Keyword[self]/CurrNominal: self[#FooEnum.Type#]; name=self
// FOO_ENUM_DOT_INVALID-DAG: Keyword/CurrNominal: Type[#FooEnum.Type#]; name=Type
// FOO_ENUM_DOT_INVALID-DAG: Decl[EnumElement]/CurrNominal: Foo1[#FooEnum#]{{; name=.+$}}
// FOO_ENUM_DOT_INVALID-DAG: Decl[EnumElement]/CurrNominal: Foo2[#FooEnum#]{{; name=.+$}}
// FOO_ENUM_DOT_INVALID-DAG: Decl[StaticVar]/CurrNominal: alias1[#FooEnum#]{{; name=.+$}}
// FOO_ENUM_DOT_INVALID-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): FooEnum#})[#(into: inout Hasher) -> Void#]{{; name=.+$}}
// FOO_ENUM_DOT_INVALID-DAG: Decl[TypeAlias]/CurrNominal: AllCases[#[FooEnum]#]{{; name=.+$}}
// FOO_ENUM_DOT_INVALID-DAG: Decl[StaticVar]/CurrNominal: allCases[#[FooEnum]#]{{; name=.+$}}
// FOO_ENUM_DOT_CONTEXT-DAG: Keyword[self]/CurrNominal: self[#FooEnum.Type#]; name=self
// FOO_ENUM_DOT_CONTEXT-DAG: Keyword/CurrNominal: Type[#FooEnum.Type#]; name=Type
// FOO_ENUM_DOT_CONTEXT-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Convertible]: Foo1[#FooEnum#]{{; name=.+$}}
@@ -256,7 +265,7 @@ func testSwitchWithQualification1(e: FooEnum) {
func testSwitchExprError1() {
switch unknown_var {
case FooEnum.#^ENUM_SW_EXPR_ERROR_1?check=FOO_ENUM_DOT^#
case FooEnum.#^ENUM_SW_EXPR_ERROR_1?check=FOO_ENUM_DOT_INVALID^#
}
}

View File

@@ -43,9 +43,20 @@ func foo(_ x: Int) {
}
// RUN: %complete-test -tok=EXPR1 %s -raw | %FileCheck %s -check-prefix=LITERALS
// RUN: %complete-test -tok=EXPR2 %s -raw | %FileCheck %s -check-prefix=LITERALS
// RUN: %complete-test -tok=EXPR2 %s -raw | %FileCheck %s -check-prefix=LITERALS_PLUS
// RUN: %complete-test -tok=EXPR2 %s -raw | %FileCheck %s -check-prefix=LITERALS_PLUS_NOT
let x1 = #^EXPR1^#
x1 + #^EXPR2^#
// LITERALS_PLUS: key.kind: source.lang.swift.literal.integer
// LITERALS_PLUS: key.kind: source.lang.swift.literal.string
// LITERALS_PLUS: key.sourcetext: "\"<#{{.*}}#>\""
// LITERALS_PLUS: key.kind: source.lang.swift.literal.array
// LITERALS_PLUS: key.sourcetext: "[<#{{.*}}#>]"
// LITERALS_PLUS_NOT-NOT: key.kind: source.lang.swift.literal.boolean
// LITERALS_PLUS_NOT-NOT: key.kind: source.lang.swift.literal.dictionary
// LITERALS_PLUS_NOT-NOT: key.kind: source.lang.swift.literal.tuple
// LITERALS_PLUS_NOT-NOT: key.kind: source.lang.swift.literal.nil
// RUN: %complete-test -tok=EXPR3 %s -raw | %FileCheck %s -check-prefix=LITERAL_BOOL
if #^EXPR3^# { }

View File

@@ -0,0 +1,8 @@
// RUN: %swift-ide-test -code-completion -code-completion-token COMPLETE -source-filename %s
// https://github.com/swiftlang/swift/issues/77335
// Make sure we don't crash
func foo(_ x: X!) {
x.#^COMPLETE^#
}