From 7e5dfc28fa4a4d89324240cbe5f5b86c5c094520 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sat, 4 Oct 2025 12:56:52 +0100 Subject: [PATCH 1/3] [CS] Split out element archetype handling in `resolveType` Make sure we do this after we transform the type as otherwise we could skip resolving type variables and let them escape. --- lib/Sema/CSDiagnostics.cpp | 10 +++++----- .../8a65840ca91fedd9.swift | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename validation-test/{compiler_crashers_2 => compiler_crashers_2_fixed}/8a65840ca91fedd9.swift (89%) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 21bf83540937f..91e1e265769dc 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -122,17 +122,17 @@ Type FailureDiagnostic::resolveType(Type rawType, bool reconstituteSugar, : resolvedType; } - if (type->hasElementArchetype()) { - auto *env = getDC()->getGenericEnvironmentOfContext(); - return env->mapElementTypeIntoPackContext(type); - } - if (type->isPlaceholder()) return ErrorType::get(type->getASTContext()); return std::nullopt; }); + if (rawType->hasElementArchetype()) { + auto *env = getDC()->getGenericEnvironmentOfContext(); + rawType = env->mapElementTypeIntoPackContext(rawType); + } + if (reconstituteSugar) rawType = rawType->reconstituteSugar(/*recursive*/ true); return wantRValue ? rawType->getRValueType() : rawType; diff --git a/validation-test/compiler_crashers_2/8a65840ca91fedd9.swift b/validation-test/compiler_crashers_2_fixed/8a65840ca91fedd9.swift similarity index 89% rename from validation-test/compiler_crashers_2/8a65840ca91fedd9.swift rename to validation-test/compiler_crashers_2_fixed/8a65840ca91fedd9.swift index 5af3e9c8dd253..ebf6724ba0f30 100644 --- a/validation-test/compiler_crashers_2/8a65840ca91fedd9.swift +++ b/validation-test/compiler_crashers_2_fixed/8a65840ca91fedd9.swift @@ -1,3 +1,3 @@ // {"kind":"typecheck","signature":"swift::TypeChecker::typesSatisfyConstraint(swift::Type, swift::Type, bool, swift::constraints::ConstraintKind, swift::DeclContext*, bool*)","signatureAssert":"Assertion failed: (!type1->getRecursiveProperties().isSolverAllocated() && !type2->getRecursiveProperties().isSolverAllocated() && \"Cannot escape solver-allocated types into a nested ConstraintSystem\"), function typesSatisfyConstraint"} -// RUN: not --crash %target-swift-frontend -typecheck %s +// RUN: not %target-swift-frontend -typecheck %s func a(c : repeat each b) { repeat !(d c From 669a2ce9b068cb25ee7aa60ca0613d3996994f14 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sat, 4 Oct 2025 12:56:52 +0100 Subject: [PATCH 2/3] [CS] Sink placeholder handling logic into `Solution::simplifyType` Move the logic from `FailureDiagnostic::resolveType` into `Solution::simplifyType` to allow completion to use it too. While here, also handle cases where the placeholder is from a different member of the equivalence class to the generic parameter. --- lib/Sema/CSDiagnostics.cpp | 32 +-------- lib/Sema/ConstraintSystem.cpp | 71 ++++++++++++++++++- test/Constraints/diag_missing_arg.swift | 4 +- test/Constraints/generics.swift | 6 +- test/Constraints/pack_expansion_types.swift | 6 +- test/Constraints/tuple_arguments.swift | 2 +- test/Generics/issue-55666.swift | 12 ++-- test/IDE/complete_constructor.swift | 14 ++-- test/IDE/complete_crashes.swift | 2 +- test/IDE/complete_enum_elements.swift | 24 +++---- test/IDE/complete_from_swift_module.swift | 12 ++-- test/IDE/complete_name_lookup.swift | 10 +-- test/IDE/complete_subscript.swift | 8 +-- test/IDE/complete_uninferred_generic.swift | 2 +- test/IDE/complete_value_expr.swift | 12 ++-- test/Misc/misc_diagnostics.swift | 2 +- .../constraint_failure.swift | 2 +- .../IDE/crashers_fixed/d9ea33a8feaee63c.swift | 3 + .../Sema/SwiftUI/rdar88256059.swift | 2 +- .../rdar50869732.swift | 4 +- 20 files changed, 136 insertions(+), 94 deletions(-) create mode 100644 validation-test/IDE/crashers_fixed/d9ea33a8feaee63c.swift diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 91e1e265769dc..cfa974789ccd8 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -96,37 +96,7 @@ Type FailureDiagnostic::getRawType(ASTNode node) const { Type FailureDiagnostic::resolveType(Type rawType, bool reconstituteSugar, bool wantRValue) const { - rawType = rawType.transformRec([&](Type type) -> std::optional { - if (auto *typeVar = type->getAs()) { - auto resolvedType = S.simplifyType(typeVar); - - if (!resolvedType->hasError()) - return resolvedType; - - // If type variable was simplified to an unresolved pack expansion - // type, let's examine its original pattern type because it could - // contain type variables replaceable with their generic parameter - // types. - if (auto *expansion = resolvedType->getAs()) { - auto *locator = typeVar->getImpl().getLocator(); - auto *openedExpansionTy = - locator->castLastElementTo() - .getOpenedType(); - auto patternType = resolveType(openedExpansionTy->getPatternType()); - return PackExpansionType::get(patternType, expansion->getCountType()); - } - - Type GP = typeVar->getImpl().getGenericParameter(); - return resolvedType->is() && GP - ? ErrorType::get(GP) - : resolvedType; - } - - if (type->isPlaceholder()) - return ErrorType::get(type->getASTContext()); - - return std::nullopt; - }); + rawType = S.simplifyType(rawType); if (rawType->hasElementArchetype()) { auto *env = getDC()->getGenericEnvironmentOfContext(); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index dde763f41512a..84e8dc990c07f 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1861,6 +1861,71 @@ void Solution::recordSingleArgMatchingChoice(ConstraintLocator *locator) { MatchCallArgumentResult::forArity(1)}); } +static GenericTypeParamType * +getGenericParamForHoleTypeVar(TypeVariableType *tv, const Solution &S) { + auto getGenericParam = [](TypeVariableType *tv) -> GenericTypeParamType * { + auto *gp = tv->getImpl().getGenericParameter(); + if (!gp) + return nullptr; + // Note we only consider generic parameters with underlying decls since for + // diagnostics we want something we can print, and for completion we want + // something we can extract a GenericEnvironment to produce an archetype. + return gp->getDecl() ? gp : nullptr; + }; + + if (auto *gp = getGenericParam(tv)) + return gp; + + // Sometimes we run into cases where the originator of a hole isn't for + // the generic parameter, instead it's for a member of its equivalence + // class. Handle this by looking through all the bindings to see if we have + // the same hole bound to a generic parameter type variable. + for (auto &binding : S.typeBindings) { + if (auto *hole = binding.second->getAs()) { + if (hole->getOriginator().dyn_cast() == tv) { + if (auto *gp = getGenericParam(binding.first)) + return gp; + } + } + } + return nullptr; +} + +static Type replacePlaceholderType(PlaceholderType *placeholder, + const Solution &S) { + auto &ctx = S.getConstraintSystem().getASTContext(); + auto origTy = [&]() -> Type { + auto orig = placeholder->getOriginator(); + if (auto *tv = orig.dyn_cast()) + return tv; + if (auto *dmt = orig.dyn_cast()) + return dmt; + return Type(); + }(); + if (!origTy) + return ErrorType::get(ctx); + + // Try replace the type variable with its original generic parameter type. + auto replacement = origTy.transformRec([&](Type ty) -> std::optional { + auto *tv = dyn_cast(ty.getPointer()); + if (!tv) + return std::nullopt; + + auto *gp = getGenericParamForHoleTypeVar(tv, S); + if (!gp) + return std::nullopt; + + return Type(gp); + }); + if (isa(replacement.getPointer())) + return ErrorType::get(ctx); + + // Return an ErrorType with the replacement as the original type. Note that + // if we failed to replace a type variable with a generic parameter in a + // dependent member, `ErrorType::get` will fold it away. + return ErrorType::get(replacement); +} + Type Solution::simplifyType(Type type, bool wantInterfaceType) const { // If we've been asked for an interface type, start by mapping any archetypes // out of context. @@ -1899,7 +1964,11 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const { return type; auto *typePtr = type.getPointer(); - if (isa(typePtr) || isa(typePtr)) + + if (auto *placeholder = dyn_cast(typePtr)) + return replacePlaceholderType(placeholder, *this); + + if (isa(typePtr)) return ErrorType::get(ctx); return std::nullopt; diff --git a/test/Constraints/diag_missing_arg.swift b/test/Constraints/diag_missing_arg.swift index c1311214ebb0d..8f9c2199120c9 100644 --- a/test/Constraints/diag_missing_arg.swift +++ b/test/Constraints/diag_missing_arg.swift @@ -19,11 +19,11 @@ func attributedInOutFunc(x: inout @convention(c) () -> Int32) {} // expected-not attributedInOutFunc() // expected-error {{missing argument for parameter 'x' in call}} {{21-21=x: &<#@convention(c) () -> Int32#>}} func genericFunc1(x: T) {} // expected-note * {{here}} -genericFunc1() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#_#>}} +genericFunc1() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#T#>}} protocol P {} func genericFunc2(x: T) {} // expected-note * {{here}} -genericFunc2() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#_#>}} +genericFunc2() // expected-error {{missing argument for parameter 'x' in call}} {{14-14=x: <#T#>}} typealias MyInt = Int func aliasedFunc(x: MyInt) {} // expected-note * {{here}} diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index daf7bdfcd1392..764f3c924cb11 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -1040,8 +1040,8 @@ func test_requirement_failures_in_ambiguous_context() { // rdar://106054263 - failed to produce a diagnostic upon generic argument mismatch func test_mismatches_with_dependent_member_generic_arguments() { struct Binding {} - // expected-note@-1 {{arguments to generic parameter 'T' ('Double?' and 'Data.SomeAssociated') are expected to be equal}} - // expected-note@-2 {{arguments to generic parameter 'U' ('Int' and 'Data.SomeAssociated') are expected to be equal}} + // expected-note@-1 {{arguments to generic parameter 'T' ('Double?' and 'Data.SomeAssociated' (aka 'String')) are expected to be equal}} + // expected-note@-2 {{arguments to generic parameter 'U' ('Int' and 'Data.SomeAssociated' (aka 'String')) are expected to be equal}} struct Data : SomeProtocol { typealias SomeAssociated = String @@ -1058,7 +1058,7 @@ func test_mismatches_with_dependent_member_generic_arguments() { test2(Optional(nil), Data()) // expected-error@-1 {{cannot convert value of type 'Optional' to expected argument type 'Optional'}} - // expected-note@-2 {{arguments to generic parameter 'Wrapped' ('Int' and 'Data.SomeAssociated') are expected to be equal}} + // expected-note@-2 {{arguments to generic parameter 'Wrapped' ('Int' and 'Data.SomeAssociated' (aka 'String')) are expected to be equal}} } extension Dictionary where Value == Any { // expected-note {{where 'Value' = 'any P'}} diff --git a/test/Constraints/pack_expansion_types.swift b/test/Constraints/pack_expansion_types.swift index f42c80a79758d..c7868d47a26e7 100644 --- a/test/Constraints/pack_expansion_types.swift +++ b/test/Constraints/pack_expansion_types.swift @@ -240,10 +240,10 @@ func patternInstantiationConcreteValid() { func patternInstantiationConcreteInvalid() { let _: Set = patternInstantiationTupleTest1() - // expected-error@-1 {{cannot convert value of type '(repeat Array<_>)' to specified type 'Set'}} + // expected-error@-1 {{cannot convert value of type 'Array<_>' to specified type 'Set'}} // expected-error@-2 {{could not infer pack element #0 from context}} - let _: (Array, Set) = patternInstantiationTupleTest1() // expected-error {{'(repeat Array)' is not convertible to '(Array, Set)', tuples have a different number of elements}} + let _: (Array, Set) = patternInstantiationTupleTest1() // expected-error {{cannot convert value of type '(Array, Array<_>)' to specified type '(Array, Set)'}} // expected-error@-1 {{could not infer pack element #1 from context}} } @@ -274,7 +274,7 @@ func patternInstantiationGenericInvalid(t: repeat each T) { let _: (repeat Set) = patternInstantiationTupleTest1() // expected-error {{cannot convert value of type '(repeat Array)' to specified type '(repeat Set)}} // expected-error@-1 {{generic parameter 'each T' could not be inferred}} - let _: (repeat Array, Set) = patternInstantiationTupleTest1() // expected-error {{'(repeat Array)' is not convertible to '(repeat Array, Set)', tuples have a different number of elements}} + let _: (repeat Array, Set) = patternInstantiationTupleTest1() // expected-error {{cannot convert value of type '(repeat Array, Array<_>)' to specified type '(repeat Array, Set)'}} // expected-error@-1 {{could not infer pack element #1 from context}} } diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift index 9f4498169cef1..a1c4d635fd180 100644 --- a/test/Constraints/tuple_arguments.swift +++ b/test/Constraints/tuple_arguments.swift @@ -1728,7 +1728,7 @@ do { do { func f(_: Int...) {} let _ = [(1, 2, 3)].map(f) // expected-error {{no exact matches in call to instance method 'map'}} - // expected-note@-1 {{found candidate with type '(((Int, Int, Int)) -> _) -> Array<_>'}} + // expected-note@-1 2{{found candidate with type '(((Int, Int, Int)) -> T) -> [T]'}} } // rdar://problem/48443263 - cannot convert value of type '() -> Void' to expected argument type '(_) -> Void' diff --git a/test/Generics/issue-55666.swift b/test/Generics/issue-55666.swift index 812c22d6f7478..b6dcebcf67d1e 100644 --- a/test/Generics/issue-55666.swift +++ b/test/Generics/issue-55666.swift @@ -7,16 +7,16 @@ struct W {} struct S { init(){} // expected-note@+2 {{where 'C1.Element' = 'W', 'main.W' = 'main.W'}} - // expected-note@+1 {{where 'C1.Element' = 'W', 'W' = 'W.Element>'}} + // expected-note@+1 {{where 'C1.Element' = 'W', 'W' = 'W'}} init(_ c2: W) where C2: Collection, C1.Element == W {} - // expected-note@+1 {{where 'C1.Element' = 'W', 'W' = 'W.Element>'}} + // expected-note@+1 {{where 'C1.Element' = 'W', 'W' = 'W'}} static func f(_ c2: W) where C2: Collection, C1.Element == W {} - // expected-note@+1 {{where 'C1.Element' = 'W', 'W' = 'W.Element>'}} + // expected-note@+1 {{where 'C1.Element' = 'W', 'W' = 'W'}} func instancef(_ c2: W) where C2: Collection, C1.Element == W {} } -let _ = S<[W]>(W<[Int]>()) // expected-error{{initializer 'init(_:)' requires the types 'W' and 'W.Element>' be equivalent}} -let _ = S<[W]>.f(W<[Int]>()) // expected-error{{static method 'f' requires the types 'W' and 'W.Element>' be equivalent}} -let _ = S<[W]>().instancef(W<[Int]>()) // expected-error{{instance method 'instancef' requires the types 'W' and 'W.Element>' be equivalent}} +let _ = S<[W]>(W<[Int]>()) // expected-error{{initializer 'init(_:)' requires the types 'W' and 'W' be equivalent}} +let _ = S<[W]>.f(W<[Int]>()) // expected-error{{static method 'f' requires the types 'W' and 'W' be equivalent}} +let _ = S<[W]>().instancef(W<[Int]>()) // expected-error{{instance method 'instancef' requires the types 'W' and 'W' be equivalent}} // Archetypes requirement failure func genericFunc(_ c2: W, c1: C1.Type) where C1.Element == W { diff --git a/test/IDE/complete_constructor.swift b/test/IDE/complete_constructor.swift index 9f810eb23681f..fa7d708f9614c 100644 --- a/test/IDE/complete_constructor.swift +++ b/test/IDE/complete_constructor.swift @@ -315,15 +315,15 @@ func testDependentTypeInClosure() { // DEPENDENT_IN_CLOSURE_3-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init({#arg: DataType#}, {#fn: () -> Data.Content##() -> Data.Content#})[#DependentTypeInClosure#]; let _ = DependentTypeInClosure(#^DEPENDENT_IN_CLOSURE_1^#) -// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg): DataType#}, {#fn: (_) -> Void##(_) -> Void#}[')'][#DependentTypeInClosure#]; -// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: DataType#}, {#fn: () -> _##() -> _#}[')'][#DependentTypeInClosure#]; +// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg): DataType#}, {#fn: (Data.Content) -> Void##(Data.Content) -> Void#}[')'][#DependentTypeInClosure#]; +// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: DataType#}, {#fn: () -> Data.Content##() -> Data.Content#}[')'][#DependentTypeInClosure#]; let _ = DependentTypeInClosure.#^DEPENDENT_IN_CLOSURE_2^# // DEPENDENT_IN_CLOSURE_2: Begin completions, 4 items -// DEPENDENT_IN_CLOSURE_2-DAG: Keyword[self]/CurrNominal: self[#DependentTypeInClosure<_>.Type#]; name=self -// DEPENDENT_IN_CLOSURE_2-DAG: Keyword/CurrNominal: Type[#DependentTypeInClosure<_>.Type#]; name=Type -// DEPENDENT_IN_CLOSURE_2-DAG: Decl[Constructor]/CurrNominal: init({#(arg): _#}, {#fn: (_.Content) -> Void##(_.Content) -> Void#})[#DependentTypeInClosure<_>#]; name=init(:fn:) -// DEPENDENT_IN_CLOSURE_2-DAG: Decl[Constructor]/CurrNominal: init({#arg: _#}, {#fn: () -> _.Content##() -> _.Content#})[#DependentTypeInClosure<_>#]; name=init(arg:fn:) +// DEPENDENT_IN_CLOSURE_2-DAG: Keyword[self]/CurrNominal: self[#DependentTypeInClosure.Type#]; name=self +// DEPENDENT_IN_CLOSURE_2-DAG: Keyword/CurrNominal: Type[#DependentTypeInClosure.Type#]; name=Type +// DEPENDENT_IN_CLOSURE_2-DAG: Decl[Constructor]/CurrNominal: init({#(arg): Data#}, {#fn: (Data.Content) -> Void##(Data.Content) -> Void#})[#DependentTypeInClosure#]; name=init(:fn:) +// DEPENDENT_IN_CLOSURE_2-DAG: Decl[Constructor]/CurrNominal: init({#arg: Data#}, {#fn: () -> Data.Content##() -> Data.Content#})[#DependentTypeInClosure#]; name=init(arg:fn:) } struct InitWithUnresolved where Data.Content: Comparable { init(arg: Data, fn: (Data.Content) -> Void) {} @@ -334,7 +334,7 @@ extension InitWithUnresolved where Self.Data: Comparable { func testInitWithUnresolved() { let _ = InitWithUnresolved(#^INIT_WITH_UNRESOLVEDTYPE_1^# // INIT_WITH_UNRESOLVEDTYPE_1: Begin completions, 2 items -// INIT_WITH_UNRESOLVEDTYPE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: DataType#}, {#fn: (_) -> Void##(_) -> Void#}[')'][#InitWithUnresolved#]; +// INIT_WITH_UNRESOLVEDTYPE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: DataType#}, {#fn: (Data.Content) -> Void##(Data.Content) -> Void#}[')'][#InitWithUnresolved#]; // INIT_WITH_UNRESOLVEDTYPE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg2: DataType#}[')'][#InitWithUnresolved#]; } diff --git a/test/IDE/complete_crashes.swift b/test/IDE/complete_crashes.swift index 708084ae4bc01..19603004d9ec6 100644 --- a/test/IDE/complete_crashes.swift +++ b/test/IDE/complete_crashes.swift @@ -381,6 +381,6 @@ extension P_80635105 { func test_80635105() { let fn = { x in S_80635105.#^RDAR_80635105^# - // RDAR_80635105: Decl[InstanceMethod]/Super: foo({#(self): S_80635105<_>#})[#(P_80635105.T) -> Void#]; name=foo + // RDAR_80635105: Decl[InstanceMethod]/Super: foo({#(self): S_80635105#})[#(P_80635105.T) -> Void#]; name=foo } } diff --git a/test/IDE/complete_enum_elements.swift b/test/IDE/complete_enum_elements.swift index a7711055ba305..6beb9d7c56d0d 100644 --- a/test/IDE/complete_enum_elements.swift +++ b/test/IDE/complete_enum_elements.swift @@ -153,14 +153,14 @@ enum BazEnum { // BAZ_INT_ENUM_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#BazEnum.Type#]; name=self // BAZ_INT_ENUM_NO_DOT-DAG: Keyword/CurrNominal: .Type[#BazEnum.Type#]; name=Type -// BAZ_T_ENUM_NO_DOT-DAG: Decl[EnumElement]/CurrNominal: .Baz1[#BazEnum<_>#]{{; name=.+$}} -// BAZ_T_ENUM_NO_DOT-DAG: Decl[EnumElement]/CurrNominal: .Baz2({#_#})[#BazEnum<_>#]{{; name=.+$}} -// BAZ_T_ENUM_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .bazInstanceFunc({#(self): &BazEnum<_>#})[#() -> Void#]{{; name=.+$}} +// BAZ_T_ENUM_NO_DOT-DAG: Decl[EnumElement]/CurrNominal: .Baz1[#BazEnum#]{{; name=.+$}} +// BAZ_T_ENUM_NO_DOT-DAG: Decl[EnumElement]/CurrNominal: .Baz2({#T#})[#BazEnum#]{{; name=.+$}} +// BAZ_T_ENUM_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .bazInstanceFunc({#(self): &BazEnum#})[#() -> Void#]{{; name=.+$}} // BAZ_T_ENUM_NO_DOT-DAG: Decl[StaticVar]/CurrNominal: .staticVar[#Int#]{{; name=.+$}} -// BAZ_T_ENUM_NO_DOT-DAG: Decl[StaticVar]/CurrNominal: .staticVarT[#_#]{{; name=.+$}} +// BAZ_T_ENUM_NO_DOT-DAG: Decl[StaticVar]/CurrNominal: .staticVarT[#T#]{{; name=.+$}} // BAZ_T_ENUM_NO_DOT-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Invalid]: .bazStaticFunc()[#Void#]{{; name=.+$}} -// BAZ_T_ENUM_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#BazEnum<_>.Type#]; name=self -// BAZ_T_ENUM_NO_DOT-DAG: Keyword/CurrNominal: .Type[#BazEnum<_>.Type#]; name=Type +// BAZ_T_ENUM_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#BazEnum.Type#]; name=self +// BAZ_T_ENUM_NO_DOT-DAG: Keyword/CurrNominal: .Type[#BazEnum.Type#]; name=Type // BAZ_INT_ENUM_DOT: Begin completions, 8 items // BAZ_INT_ENUM_DOT-DAG: Keyword[self]/CurrNominal: self[#BazEnum.Type#]; name=self @@ -173,13 +173,13 @@ enum BazEnum { // BAZ_INT_ENUM_DOT-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Invalid]: bazStaticFunc()[#Void#]{{; name=.+$}} // BAZ_T_ENUM_DOT: Begin completions, 8 items -// BAZ_T_ENUM_DOT-DAG: Keyword[self]/CurrNominal: self[#BazEnum<_>.Type#]; name=self -// BAZ_T_ENUM_DOT-DAG: Keyword/CurrNominal: Type[#BazEnum<_>.Type#]; name=Type -// BAZ_T_ENUM_DOT-DAG: Decl[EnumElement]/CurrNominal: Baz1[#BazEnum<_>#]{{; name=.+$}} -// BAZ_T_ENUM_DOT-DAG: Decl[EnumElement]/CurrNominal: Baz2({#_#})[#BazEnum<_>#]{{; name=.+$}} -// BAZ_T_ENUM_DOT-DAG: Decl[InstanceMethod]/CurrNominal: bazInstanceFunc({#(self): &BazEnum<_>#})[#() -> Void#]{{; name=.+$}} +// BAZ_T_ENUM_DOT-DAG: Keyword[self]/CurrNominal: self[#BazEnum.Type#]; name=self +// BAZ_T_ENUM_DOT-DAG: Keyword/CurrNominal: Type[#BazEnum.Type#]; name=Type +// BAZ_T_ENUM_DOT-DAG: Decl[EnumElement]/CurrNominal: Baz1[#BazEnum#]{{; name=.+$}} +// BAZ_T_ENUM_DOT-DAG: Decl[EnumElement]/CurrNominal: Baz2({#T#})[#BazEnum#]{{; name=.+$}} +// BAZ_T_ENUM_DOT-DAG: Decl[InstanceMethod]/CurrNominal: bazInstanceFunc({#(self): &BazEnum#})[#() -> Void#]{{; name=.+$}} // BAZ_T_ENUM_DOT-DAG: Decl[StaticVar]/CurrNominal: staticVar[#Int#]{{; name=.+$}} -// BAZ_T_ENUM_DOT-DAG: Decl[StaticVar]/CurrNominal: staticVarT[#_#]{{; name=.+$}} +// BAZ_T_ENUM_DOT-DAG: Decl[StaticVar]/CurrNominal: staticVarT[#T#]{{; name=.+$}} // BAZ_T_ENUM_DOT-DAG: Decl[StaticMethod]/CurrNominal/TypeRelation[Invalid]: bazStaticFunc()[#Void#]{{; name=.+$}} enum QuxEnum : Int { diff --git a/test/IDE/complete_from_swift_module.swift b/test/IDE/complete_from_swift_module.swift index 0c9d86feca678..7be6ca09904d3 100644 --- a/test/IDE/complete_from_swift_module.swift +++ b/test/IDE/complete_from_swift_module.swift @@ -98,16 +98,16 @@ func testCompleteModuleQualified2() { func testCompleteModuleQualified3() { foo_swift_module.BarGenericSwiftStruct1#^MODULE_QUALIFIED_3^# } -// MODULE_QUALIFIED_3-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ({#t: _#})[#BarGenericSwiftStruct1<_>#]; name=(t:) -// MODULE_QUALIFIED_3-DAG: Decl[InstanceMethod]/CurrNominal: .bar1InstanceFunc({#(self): BarGenericSwiftStruct1<_>#})[#() -> Void#]; name=bar1InstanceFunc(:) +// MODULE_QUALIFIED_3-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ({#t: T#})[#BarGenericSwiftStruct1#]; name=(t:) +// MODULE_QUALIFIED_3-DAG: Decl[InstanceMethod]/CurrNominal: .bar1InstanceFunc({#(self): BarGenericSwiftStruct1#})[#() -> Void#]; name=bar1InstanceFunc(:) func testCompleteModuleQualified4() { foo_swift_module.BarGenericSwiftStruct2#^MODULE_QUALIFIED_4^# } -// MODULE_QUALIFIED_4-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ({#t: _#}, {#u: _#})[#BarGenericSwiftStruct2<_, _>#]; name=(t:u:) -// MODULE_QUALIFIED_4-DAG: Decl[InstanceMethod]/CurrNominal: .bar2InstanceFunc({#(self): BarGenericSwiftStruct2<_, _>#})[#() -> Void#]; name=bar2InstanceFunc(:) -// MODULE_QUALIFIED_4-DAG: Keyword[self]/CurrNominal: .self[#BarGenericSwiftStruct2<_, _>.Type#]; name=self -// MODULE_QUALIFIED_4-DAG: Keyword/CurrNominal: .Type[#BarGenericSwiftStruct2<_, _>.Type#]; name=Type +// MODULE_QUALIFIED_4-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ({#t: T#}, {#u: U#})[#BarGenericSwiftStruct2#]; name=(t:u:) +// MODULE_QUALIFIED_4-DAG: Decl[InstanceMethod]/CurrNominal: .bar2InstanceFunc({#(self): BarGenericSwiftStruct2#})[#() -> Void#]; name=bar2InstanceFunc(:) +// MODULE_QUALIFIED_4-DAG: Keyword[self]/CurrNominal: .self[#BarGenericSwiftStruct2.Type#]; name=self +// MODULE_QUALIFIED_4-DAG: Keyword/CurrNominal: .Type[#BarGenericSwiftStruct2.Type#]; name=Type func testCompleteModuleQualified5() { corrupted_module.#^MODULE_QUALIFIED_5^# diff --git a/test/IDE/complete_name_lookup.swift b/test/IDE/complete_name_lookup.swift index 0a49716d458eb..1472683fe63d1 100644 --- a/test/IDE/complete_name_lookup.swift +++ b/test/IDE/complete_name_lookup.swift @@ -45,8 +45,8 @@ extension ObservableConvertibleType { return CatchSequence.#^CATCHSEQUENCE_DOT^# } } -// CATCHSEQUENCE_DOT-DAG: Keyword[self]/CurrNominal: self[#CatchSequence<_>.Type#]; name=self -// CATCHSEQUENCE_DOT-DAG: Keyword/CurrNominal: Type[#CatchSequence<_>.Type#]; name=Type -// CATCHSEQUENCE_DOT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#CatchSequence<_>#]; name=init() -// CATCHSEQUENCE_DOT-DAG: Decl[StaticMethod]/Super/TypeRelation[Convertible]: catchError()[#Observable.T>#]; name=catchError() -// CATCHSEQUENCE_DOT-DAG: Decl[TypeAlias]/Super: T[#Observable<_.Element.T>.T#]; name=T +// CATCHSEQUENCE_DOT-DAG: Keyword[self]/CurrNominal: self[#CatchSequence.Type#]; name=self +// CATCHSEQUENCE_DOT-DAG: Keyword/CurrNominal: Type[#CatchSequence.Type#]; name=Type +// CATCHSEQUENCE_DOT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init()[#CatchSequence#]; name=init() +// CATCHSEQUENCE_DOT-DAG: Decl[StaticMethod]/Super/TypeRelation[Convertible]: catchError()[#Observable.T>#]; name=catchError() +// CATCHSEQUENCE_DOT-DAG: Decl[TypeAlias]/Super: T[#Observable.T#]; name=T diff --git a/test/IDE/complete_subscript.swift b/test/IDE/complete_subscript.swift index 81ad70cceccd6..8f097dff2d5fb 100644 --- a/test/IDE/complete_subscript.swift +++ b/test/IDE/complete_subscript.swift @@ -12,10 +12,10 @@ struct MyStruct { func test1() { let _ = MyStruct #^METATYPE_UNRESOLVED^# // METATYPE_UNRESOLVED: Begin completions, 4 items -// METATYPE_UNRESOLVED-DAG: Decl[Subscript]/CurrNominal: [{#(x): Int#}, {#static: _#}][#MyStruct<_>#]; -// METATYPE_UNRESOLVED-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ()[#MyStruct<_>#]; -// METATYPE_UNRESOLVED-DAG: Keyword[self]/CurrNominal: .self[#MyStruct<_>.Type#]; -// METATYPE_UNRESOLVED-DAG: Keyword/CurrNominal: .Type[#MyStruct<_>.Type#]; +// METATYPE_UNRESOLVED-DAG: Decl[Subscript]/CurrNominal: [{#(x): Int#}, {#static: T#}][#MyStruct#]; +// METATYPE_UNRESOLVED-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ()[#MyStruct#]; +// METATYPE_UNRESOLVED-DAG: Keyword[self]/CurrNominal: .self[#MyStruct.Type#]; +// METATYPE_UNRESOLVED-DAG: Keyword/CurrNominal: .Type[#MyStruct.Type#]; let _ = MyStruct[#^METATYPE_UNRESOLVED_BRACKET^# // METATYPE_UNRESOLVED_BRACKET-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]: ['[']{#(x): Int#}, {#static: T#}[']'][#MyStruct#]; diff --git a/test/IDE/complete_uninferred_generic.swift b/test/IDE/complete_uninferred_generic.swift index 48bbdf4b20aee..bdb4d04c8904d 100644 --- a/test/IDE/complete_uninferred_generic.swift +++ b/test/IDE/complete_uninferred_generic.swift @@ -15,4 +15,4 @@ _ = S2()#^UNINFERRED^# // UNINFERRED-DAG: Decl[Subscript]/Super: [{#(v0): T#}][#Int#]; name=[:] // UNINFERRED-DAG: Decl[Subscript]/Super: [{#(v0): T#}][#_#]; name=[:] -// UNINFERRED-DAG: Keyword[self]/CurrNominal: .self[#S2<_>#]; name=self +// UNINFERRED-DAG: Keyword[self]/CurrNominal: .self[#S2#]; name=self diff --git a/test/IDE/complete_value_expr.swift b/test/IDE/complete_value_expr.swift index 3bb5738238e43..43f94e9a33753 100644 --- a/test/IDE/complete_value_expr.swift +++ b/test/IDE/complete_value_expr.swift @@ -1074,19 +1074,19 @@ class BuilderStyle { func testTypeCheckWithUnsolvedVariables1() { BuilderStyle().#^TC_UNSOLVED_VARIABLES_1^# } -// TC_UNSOLVED_VARIABLES_1-DAG: Keyword[self]/CurrNominal: self[#BuilderStyle<_>#]; name=self +// TC_UNSOLVED_VARIABLES_1-DAG: Keyword[self]/CurrNominal: self[#BuilderStyle#]; name=self // TC_UNSOLVED_VARIABLES_1-DAG: Decl[InstanceVar]/CurrNominal: count[#Int#]{{; name=.+$}} -// TC_UNSOLVED_VARIABLES_1-DAG: Decl[InstanceMethod]/CurrNominal: addString({#(s): String#})[#BuilderStyle<_>#]{{; name=.+$}} -// TC_UNSOLVED_VARIABLES_1-DAG: Decl[InstanceMethod]/CurrNominal: add({#(t): _#})[#BuilderStyle<_>#]{{; name=.+$}} +// TC_UNSOLVED_VARIABLES_1-DAG: Decl[InstanceMethod]/CurrNominal: addString({#(s): String#})[#BuilderStyle#]{{; name=.+$}} +// TC_UNSOLVED_VARIABLES_1-DAG: Decl[InstanceMethod]/CurrNominal: add({#(t): T#})[#BuilderStyle#]{{; name=.+$}} // TC_UNSOLVED_VARIABLES_1-DAG: Decl[InstanceMethod]/CurrNominal: get()[#Int#]{{; name=.+$}} func testTypeCheckWithUnsolvedVariables2() { BuilderStyle().addString("abc").#^TC_UNSOLVED_VARIABLES_2^# } -// TC_UNSOLVED_VARIABLES_2-DAG: Keyword[self]/CurrNominal: self[#BuilderStyle<_>#]; name=self +// TC_UNSOLVED_VARIABLES_2-DAG: Keyword[self]/CurrNominal: self[#BuilderStyle#]; name=self // TC_UNSOLVED_VARIABLES_2-DAG: Decl[InstanceVar]/CurrNominal: count[#Int#]{{; name=.+$}} -// TC_UNSOLVED_VARIABLES_2-DAG: Decl[InstanceMethod]/CurrNominal: addString({#(s): String#})[#BuilderStyle<_>#]{{; name=.+$}} -// TC_UNSOLVED_VARIABLES_2-DAG: Decl[InstanceMethod]/CurrNominal: add({#(t): _#})[#BuilderStyle<_>#]{{; name=.+$}} +// TC_UNSOLVED_VARIABLES_2-DAG: Decl[InstanceMethod]/CurrNominal: addString({#(s): String#})[#BuilderStyle#]{{; name=.+$}} +// TC_UNSOLVED_VARIABLES_2-DAG: Decl[InstanceMethod]/CurrNominal: add({#(t): T#})[#BuilderStyle#]{{; name=.+$}} // TC_UNSOLVED_VARIABLES_2-DAG: Decl[InstanceMethod]/CurrNominal: get()[#Int#]{{; name=.+$}} func testTypeCheckWithUnsolvedVariables3() { diff --git a/test/Misc/misc_diagnostics.swift b/test/Misc/misc_diagnostics.swift index 6d27d411adcc5..413d1c6921d9d 100644 --- a/test/Misc/misc_diagnostics.swift +++ b/test/Misc/misc_diagnostics.swift @@ -56,7 +56,7 @@ class A { var a: MyArray init() { a = MyArray.Type' and 'Int.Type'}} + // expected-error@-1 {{binary operator '<' cannot be applied to operands of type 'MyArray.Type' and 'Int.Type'}} // expected-error@-2 {{cannot assign value of type 'Bool' to type 'MyArray'}} } } diff --git a/test/decl/protocol/existential_member_access/constraint_failure.swift b/test/decl/protocol/existential_member_access/constraint_failure.swift index 76461f27b8f30..c3ed68e8aae73 100644 --- a/test/decl/protocol/existential_member_access/constraint_failure.swift +++ b/test/decl/protocol/existential_member_access/constraint_failure.swift @@ -76,7 +76,7 @@ do { let exist2: any UnfulfillableGenericRequirementsDerived2 exist1.method4(false) - // expected-error@-1 {{instance method 'method4' requires that 'Bool' inherit from 'Class}} + // expected-error@-1 {{instance method 'method4' requires that 'Bool' inherit from 'Class}} exist2.method4(false) // expected-error@-1 {{member 'method4' cannot be used on value of type 'any UnfulfillableGenericRequirementsDerived2'; consider using a generic constraint instead}} // expected-error@-2 {{instance method 'method4' requires that 'Bool' inherit from 'Class'}} diff --git a/validation-test/IDE/crashers_fixed/d9ea33a8feaee63c.swift b/validation-test/IDE/crashers_fixed/d9ea33a8feaee63c.swift new file mode 100644 index 0000000000000..0adea35ab82d9 --- /dev/null +++ b/validation-test/IDE/crashers_fixed/d9ea33a8feaee63c.swift @@ -0,0 +1,3 @@ +// {"kind":"complete","original":"d09c9cf7","signature":"swift::Mangle::ASTMangler::mangleTypeAsUSR(swift::Type)"} +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +try #^^# ?? (try? a.() as? b) diff --git a/validation-test/Sema/SwiftUI/rdar88256059.swift b/validation-test/Sema/SwiftUI/rdar88256059.swift index 4ddbbe90603c5..e75382818528d 100644 --- a/validation-test/Sema/SwiftUI/rdar88256059.swift +++ b/validation-test/Sema/SwiftUI/rdar88256059.swift @@ -9,7 +9,7 @@ struct MyView: View { var body: some View { Table(self.data) { - // expected-error@-1 {{expected expression in result builder 'TableColumnBuilder'}} {{23-23=<#result#>}} + // expected-error@-1 {{expected expression of type 'Columns' in result builder 'TableColumnBuilder'}} {{23-23=<#T##Columns#>}} } } } diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar50869732.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar50869732.swift index 753849a9fdb9d..b5f084757b57f 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/rdar50869732.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/rdar50869732.swift @@ -25,7 +25,7 @@ struct Empty { init() {} } -struct Test where T : P { // expected-note {{where 'T' = 'Generic<(Empty, _)>'}} +struct Test where T : P { // expected-note {{where 'T' = 'Generic<(Empty, C1)>'}} init(@Builder _: () -> T) {} } @@ -34,5 +34,5 @@ let x = G { Test { Empty() } // expected-error@-1 {{static method 'buildBlock' requires that 'Empty' conform to 'P'}} // expected-error@-2 {{missing argument for parameter #2 in call}} - // expected-error@-3 {{generic struct 'Test' requires that 'Generic<(Empty, _)>' conform to 'P'}} + // expected-error@-3 {{generic struct 'Test' requires that 'Generic<(Empty, C1)>' conform to 'P'}} } From 9e4208b69bba54a49a99a172c613fa2fbe9f4622 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sat, 4 Oct 2025 12:56:52 +0100 Subject: [PATCH 3/3] [CS] Remove custom logic from `simplifyTypeForCodeCompletion` We ought to be able to just use `simplifyType` with an additional parameter to tell it to produce archetypes. --- include/swift/Sema/ConstraintSystem.h | 6 +- lib/Sema/ConstraintSystem.cpp | 148 +++----------------------- 2 files changed, 20 insertions(+), 134 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 358893257487e..929e145baaa47 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -1677,7 +1677,11 @@ class Solution { /// \param wantInterfaceType If true, maps the resulting type out of context, /// and replaces type variables for opened generic parameters with the /// generic parameter types. Should only be used for diagnostic logic. - Type simplifyType(Type type, bool wantInterfaceType = false) const; + /// \param forCompletion If true, will produce archetypes instead of + /// ErrorTypes for generic parameter originators, which is what completion + /// currently expects for the code completion token. + Type simplifyType(Type type, bool wantInterfaceType = false, + bool forCompletion = false) const; // To aid code completion, we need to attempt to convert type placeholders // back into underlying generic parameters if possible, since type diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 84e8dc990c07f..f2c724e6db31c 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1892,7 +1892,7 @@ getGenericParamForHoleTypeVar(TypeVariableType *tv, const Solution &S) { } static Type replacePlaceholderType(PlaceholderType *placeholder, - const Solution &S) { + const Solution &S, bool forCompletion) { auto &ctx = S.getConstraintSystem().getASTContext(); auto origTy = [&]() -> Type { auto orig = placeholder->getOriginator(); @@ -1920,13 +1920,23 @@ static Type replacePlaceholderType(PlaceholderType *placeholder, if (isa(replacement.getPointer())) return ErrorType::get(ctx); + // For completion, we want to produce an archetype instead of an ErrorType + // for a top-level generic parameter. + // FIXME: This is pretty weird, we're producing a contextual type outside of + // the context it exists in. We ought to see if we can make the completion + // logic work with ErrorTypes instead. + if (forCompletion) { + if (auto *GP = replacement->getAs()) + return GP->getDecl()->getInnermostDeclContext()->mapTypeIntoContext(GP); + } // Return an ErrorType with the replacement as the original type. Note that // if we failed to replace a type variable with a generic parameter in a // dependent member, `ErrorType::get` will fold it away. return ErrorType::get(replacement); } -Type Solution::simplifyType(Type type, bool wantInterfaceType) const { +Type Solution::simplifyType(Type type, bool wantInterfaceType, + bool forCompletion) const { // If we've been asked for an interface type, start by mapping any archetypes // out of context. if (wantInterfaceType) @@ -1966,7 +1976,7 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const { auto *typePtr = type.getPointer(); if (auto *placeholder = dyn_cast(typePtr)) - return replacePlaceholderType(placeholder, *this); + return replacePlaceholderType(placeholder, *this, forCompletion); if (isa(typePtr)) return ErrorType::get(ctx); @@ -1980,136 +1990,8 @@ Type Solution::simplifyType(Type type, bool wantInterfaceType) const { } Type Solution::simplifyTypeForCodeCompletion(Type Ty) const { - auto &CS = getConstraintSystem(); - - // First, instantiate all type variables that we know, but don't replace - // placeholders by unresolved types. - Ty = CS.simplifyTypeImpl(Ty, [this](TypeVariableType *typeVar) -> Type { - return getFixedType(typeVar); - }); - - // Next, replace all placeholders by type variables. We know that all type - // variables now in the type originate from placeholders. - Ty = Ty.transformRec([](Type type) -> std::optional { - if (auto *placeholder = type->getAs()) { - if (auto *typeVar = - placeholder->getOriginator().dyn_cast()) { - return Type(typeVar); - } - } - - return std::nullopt; - }); - - // Replace all type variables (which must come from placeholders) by their - // generic parameters. Because we call into simplifyTypeImpl - Ty = CS.simplifyTypeImpl(Ty, [&CS, this](TypeVariableType *typeVar) -> Type { - // Code completion depends on generic parameter type being represented in - // terms of `ArchetypeType` since it's easy to extract protocol requirements - // from it. - auto getTypeVarAsArchetype = [](TypeVariableType *typeVar) -> Type { - if (auto *GP = typeVar->getImpl().getGenericParameter()) { - if (auto *GPD = GP->getDecl()) { - return GPD->getInnermostDeclContext()->mapTypeIntoContext(GP); - } - } - return Type(); - }; - - if (auto archetype = getTypeVarAsArchetype(typeVar)) { - return archetype; - } - - // Sometimes the type variable itself doesn't have have an originator that - // can be replaced by an archetype but one of its equivalent type variable - // does. - // Search thorough all equivalent type variables, looking for one that can - // be replaced by a generic parameter. - std::vector> bindings( - typeBindings.begin(), typeBindings.end()); - // Make sure we iterate the bindings in a deterministic order. - llvm::sort(bindings, [](const std::pair &lhs, - const std::pair &rhs) { - return lhs.first->getID() < rhs.first->getID(); - }); - for (auto binding : bindings) { - if (auto placeholder = binding.second->getAs()) { - if (placeholder->getOriginator().dyn_cast() == - typeVar) { - if (auto archetype = getTypeVarAsArchetype(binding.first)) { - return archetype; - } - } - } - } - - // When applying the logic below to get contextual types inside result - // builders, the code completion type variable is connected by a one-way - // constraint to a type variable in the buildBlock call, but that is not the - // type variable that represents the argument type. We need to find the type - // variable representing the argument to retrieve protocol requirements from - // it. Look for a ArgumentConversion constraint that allows us to retrieve - // the argument type var. - auto &cg = CS.getConstraintGraph(); - - // FIXME: The type variable is not going to be part of the constraint graph - // at this point unless it was created at the outermost decision level; - // otherwise it has already been rolled back! Work around this by creating - // an empty node if one doesn't exist. - cg.addTypeVariable(typeVar); - - for (auto argConstraint : cg[typeVar].getConstraints()) { - if (argConstraint->getKind() == ConstraintKind::ArgumentConversion && - argConstraint->getFirstType()->getRValueType()->isEqual(typeVar)) { - if (auto argTV = - argConstraint->getSecondType()->getAs()) { - if (auto archetype = getTypeVarAsArchetype(argTV)) { - return archetype; - } - } - } - } - - return typeVar; - }); - - // Logic to determine the contextual type inside buildBlock result builders: - // - // When completing inside a result builder, the result builder - // @ViewBuilder var body: some View { - // Text("Foo") - // #^COMPLETE^# - // } - // gets rewritten to - // @ViewBuilder var body: some View { - // let $__builder2: Text - // let $__builder0 = Text("Foo") - // let $__builder1 = #^COMPLETE^# - // $__builder2 = ViewBuilder.buildBlock($__builder0, $__builder1) - // return $__builder2 - // } - // Inside the constraint system - // let $__builder1 = #^COMPLETE^# - // gets type checked without context, so we can't know the contextual type for - // the code completion token. But we know that $__builder1 (and thus the type - // of #^COMPLETE^#) is used as the second argument to ViewBuilder.buildBlock, - // so we can extract the contextual type from that call. To do this, figure - // out the type variable that is used for $__builder1 in the buildBlock call. - // This type variable is connected to the type variable of $__builder1's - // definition by a one-way constraint. - if (auto TV = Ty->getAs()) { - for (auto constraint : CS.getConstraintGraph()[TV].getConstraints()) { - if (constraint->getKind() == ConstraintKind::OneWayEqual && - constraint->getSecondType()->isEqual(TV)) { - return simplifyTypeForCodeCompletion(constraint->getFirstType()); - } - } - } - - // Remove any remaining type variables and placeholders - Ty = simplifyType(Ty); - - return Ty->getRValueType(); + return simplifyType(Ty, /*wantInterfaceType*/ false, /*forCompletion*/ true) + ->getRValueType(); } template