From 20202f53a9743753dc304cc0c78ae1e2c2f96d9e Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 23 Sep 2025 14:36:06 +0100 Subject: [PATCH 1/2] [CS] Quick workaround for rdar://160135085 Temporarily disable the checking requirements for typealias types, and desugar the typealias since the constraint system does not currently correctly handle type variables in the underlying type. --- lib/Sema/TypeOfReference.cpp | 4 +--- test/Constraints/rdar160135085.swift | 24 +++++++++++++++++++ test/Constraints/requirement_opening.swift | 1 + test/decl/typealias/generic.swift | 16 +++++++++++++ .../078aab8ab466b66a.swift | 6 +++++ .../b31917ad9b8e4fe4.swift | 8 +++++++ 6 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 test/Constraints/rdar160135085.swift create mode 100644 validation-test/compiler_crashers_2_fixed/078aab8ab466b66a.swift create mode 100644 validation-test/compiler_crashers_2_fixed/b31917ad9b8e4fe4.swift diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 9f085732503e2..5a704ea5c5b9d 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -268,9 +268,7 @@ class InferableTypeOpener final { auto substTy = TypeAliasType::get( aliasTy->getDecl(), transform(aliasTy->getParent()), genericArgs, transform(aliasTy->getSinglyDesugaredType())); - openGenericTypeRequirements(substTy->getDecl(), - substTy->getSubstitutionMap()); - return substTy; + return substTy->getSinglyDesugaredType(); } Type transformErrorType(ErrorType *errTy) { diff --git a/test/Constraints/rdar160135085.swift b/test/Constraints/rdar160135085.swift new file mode 100644 index 0000000000000..3ac73dcff3eb9 --- /dev/null +++ b/test/Constraints/rdar160135085.swift @@ -0,0 +1,24 @@ +// RUN: %empty-directory(%t/modules) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/modules/A.swiftmodule -module-name A %t/a.swift +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/modules/B.swiftmodule -module-name B -I %t/modules %t/b.swift +// RUN: %target-swift-frontend -typecheck -I %t/modules %t/c.swift + +//--- a.swift + +public struct S { + public init(_ x: T) {} +} + +//--- b.swift + +import A +public typealias S = A.S + +//--- c.swift + +import A +import B + +_ = S(0) diff --git a/test/Constraints/requirement_opening.swift b/test/Constraints/requirement_opening.swift index df1900c4ba464..fbc62b2645d0d 100644 --- a/test/Constraints/requirement_opening.swift +++ b/test/Constraints/requirement_opening.swift @@ -1,4 +1,5 @@ // RUN: %target-typecheck-verify-swift +// REQUIRES: rdar160135085 struct K {} // expected-note 6{{'U' declared as parameter to type 'K'}} protocol Q {} diff --git a/test/decl/typealias/generic.swift b/test/decl/typealias/generic.swift index 75a893ba3d099..46995b8896481 100644 --- a/test/decl/typealias/generic.swift +++ b/test/decl/typealias/generic.swift @@ -465,3 +465,19 @@ func testSugar(_ gx: GX, _ gy: GX.GY, gz: GX.GY.E let i2: Int = gy // expected-error{{cannot convert value of type 'GX.GY' (aka 'Array') to specified type 'Int'}} let i3: Int = gz // expected-error{{cannot convert value of type 'GX.GY.Element' (aka 'Double') to specified type 'Int'}} } + +func testLocalRequirementInference(_ x: T, y: Int, s: S) { + typealias X = (T, U) where T == U.A + func foo(_ x: X) {} // expected-note {{where 'V' = 'Int'}} expected-note {{where 'T' = 'T', 'V.A' = 'S.A' (aka 'Float')}} + foo((x, y)) // expected-error {{local function 'foo' requires that 'Int' conform to 'P'}} + foo((x, s)) // expected-error {{local function 'foo' requires the types 'T' and 'S.A' (aka 'Float') be equivalent}} +} + +struct TestNestedRequirementInference { + typealias X = (T, U) where T == U.A + func foo(_ x: X) {} // expected-note {{where 'V' = 'Int'}} expected-note {{where 'T' = 'T', 'V.A' = 'S.A' (aka 'Float')}} + func bar(_ x: T, y: Int, s: S) { + foo((x, y)) // expected-error {{instance method 'foo' requires that 'Int' conform to 'P'}} + foo((x, s)) // expected-error {{instance method 'foo' requires the types 'T' and 'S.A' (aka 'Float') be equivalent}} + } +} diff --git a/validation-test/compiler_crashers_2_fixed/078aab8ab466b66a.swift b/validation-test/compiler_crashers_2_fixed/078aab8ab466b66a.swift new file mode 100644 index 0000000000000..315bb7d79a3af --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/078aab8ab466b66a.swift @@ -0,0 +1,6 @@ +// {"kind":"typecheck","signature":"swift::constraints::ConstraintSystem::openGenericParameters(swift::DeclContext*, swift::GenericSignature, llvm::SmallVectorImpl>&, swift::constraints::ConstraintLocatorBuilder, swift::constraints::PreparedOverloadBuilder*)","signatureAssert":"Assertion failed: (sig), function openGenericParameters"} +// RUN: not %target-swift-frontend -typecheck %s +class a d + typealias c : a +c diff --git a/validation-test/compiler_crashers_2_fixed/b31917ad9b8e4fe4.swift b/validation-test/compiler_crashers_2_fixed/b31917ad9b8e4fe4.swift new file mode 100644 index 0000000000000..bc8b7f7579bd1 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/b31917ad9b8e4fe4.swift @@ -0,0 +1,8 @@ +// {"kind":"typecheck","original":"0df5dc82","signature":"swift::constraints::ConstraintSystem::typeVarOccursInType(swift::TypeVariableType*, swift::Type, bool*)","signatureAssert":"Assertion failed: ((!typeVariables.empty() || hasError()) && \"Did not find type variables!\"), function getTypeVariables"} +// RUN: not %target-swift-frontend -typecheck %s +struct a = ( + > func 1 { + typealias e = f + e + typealias e = d From b2854b28bf2f03b742a72fa98da6dd901daf6a24 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 23 Sep 2025 14:36:06 +0100 Subject: [PATCH 2/2] [CS] Fix typealias handling in InferableTypeOpener For non-generic cases we can simply recurse into the underlying type, ensuring we don't crash with a null GenericSignature. For generic cases, ensure we bind outer generic parameters to their archetypes, and apply the substitutions to the original underlying type to ensure we correctly handle cases where e.g an unbound generic is passed as a generic argument to a generic typealias. rdar://160135085 --- include/swift/AST/Types.h | 6 +++- lib/AST/Type.cpp | 13 ++++++-- lib/Sema/TypeOfReference.cpp | 24 +++++++++++--- test/Constraints/requirement_opening.swift | 37 ++++++++++++++-------- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 457546af4edfd..c6b12e2e33278 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -2345,7 +2345,11 @@ class TypeAliasType final /// Retrieve the substitution map applied to the declaration's underlying /// to produce the described type. - SubstitutionMap getSubstitutionMap() const; + /// + /// \param wantContextualType If \c true, the substitution map will bind + /// outer local generic parameters to archetypes. Otherwise they will be left + /// unchanged. + SubstitutionMap getSubstitutionMap(bool wantContextualType = false) const; /// Get the direct generic arguments, which correspond to the generic /// arguments that are directly applied to the typealias declaration diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ddbb03bb29b23..c7dbc143c2a9f 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2155,7 +2155,8 @@ GenericSignature TypeAliasType::getGenericSignature() const { return typealias->getGenericSignature(); } -SubstitutionMap TypeAliasType::getSubstitutionMap() const { +SubstitutionMap +TypeAliasType::getSubstitutionMap(bool wantContextualType) const { auto genericSig = typealias->getGenericSignature(); if (!genericSig) return SubstitutionMap(); @@ -2164,8 +2165,14 @@ SubstitutionMap TypeAliasType::getSubstitutionMap() const { DeclContext *dc = typealias->getDeclContext(); if (dc->isLocalContext()) { - if (auto parentSig = dc->getGenericSignatureOfContext()) - parentSubMap = parentSig->getIdentitySubstitutionMap(); + if (auto parentSig = dc->getGenericSignatureOfContext()) { + if (wantContextualType) { + parentSubMap = + parentSig.getGenericEnvironment()->getForwardingSubstitutionMap(); + } else { + parentSubMap = parentSig->getIdentitySubstitutionMap(); + } + } } else if (auto parent = getParent()) { parentSubMap = parent->getContextSubstitutionMap(dc); } diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 5a704ea5c5b9d..463ad2c16ae74 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -261,14 +261,30 @@ class InferableTypeOpener final { } Type transformTypeAliasType(TypeAliasType *aliasTy) { + auto *TAD = aliasTy->getDecl(); + + // For a non-generic typealias, we can simply recurse into the underlying + // type. The constraint system doesn't properly handle opened types in + // the underlying type of a typealias (e.g TypeWalker won't visit them), + // so we don't preserve the sugar. + if (!TAD->getGenericSignature()) + return transform(aliasTy->getSinglyDesugaredType()); + + // Otherwise we have a generic typealias, or typealias in a generic context, + // and need to open any requirements introduced. Then we need to + // re-substitute any opened types into the underlying type. Like the + // non-generic codepath we also don't want to preserve sugar. SmallVector genericArgs; for (auto arg : aliasTy->getDirectGenericArgs()) genericArgs.push_back(transform(arg)); - auto substTy = TypeAliasType::get( - aliasTy->getDecl(), transform(aliasTy->getParent()), genericArgs, - transform(aliasTy->getSinglyDesugaredType())); - return substTy->getSinglyDesugaredType(); + auto parentTy = transform(aliasTy->getParent()); + auto subMap = TypeAliasType::get(TAD, parentTy, genericArgs, + aliasTy->getSinglyDesugaredType()) + ->getSubstitutionMap(/*wantContextualType*/ true); + + openGenericTypeRequirements(TAD, subMap); + return transform(TAD->getUnderlyingType().subst(subMap)); } Type transformErrorType(ErrorType *errTy) { diff --git a/test/Constraints/requirement_opening.swift b/test/Constraints/requirement_opening.swift index fbc62b2645d0d..1fcc27e7db37a 100644 --- a/test/Constraints/requirement_opening.swift +++ b/test/Constraints/requirement_opening.swift @@ -1,24 +1,22 @@ // RUN: %target-typecheck-verify-swift -// REQUIRES: rdar160135085 -struct K {} // expected-note 6{{'U' declared as parameter to type 'K'}} +struct K {} protocol Q {} +struct ConformingType: Q {} struct S1: ExpressibleByArrayLiteral { // expected-note 2{{where 'T' = 'K'}} init(_ x: T) {} init(arrayLiteral: T...) {} } -typealias R1 = S1 // expected-note {{where 'T' = 'K'}} expected-note 2{{where 'T' = 'K'}} +typealias R1 = S1 // expected-note 2{{where 'T' = 'K'}} func foo(_ x: K) { let _ = [x] as S1 // expected-error {{generic struct 'S1' requires that 'K' conform to 'Q'}} let _ = [x] as R1 // expected-error {{generic type alias 'R1' requires that 'K' conform to 'Q'}} - let _: S1 = [x] // expected-error {{generic struct 'S1' requires that 'K' conform to 'Q'}} - // FIXME: We ought to be able to infer 'U' here. - let _: R1 = [x] // expected-error 2 {{generic type alias 'R1' requires that 'K' conform to 'Q'}} - // expected-error@-1 2 {{generic parameter 'U' could not be inferred}} + let _: S1 = [x] // expected-error {{generic struct 'S1' requires that 'K' conform to 'Q'}} + let _: R1 = [x] // expected-error {{generic type alias 'R1' requires that 'K' conform to 'Q'}} } protocol P2 { @@ -26,11 +24,11 @@ protocol P2 { } struct S2: P2 {} // expected-note 3{{where 'A' = 'K'}} -typealias R2 = S2 // expected-note 2{{where 'A' = 'K'}} expected-note 2{{where 'A' = 'K'}} +typealias R2 = S2 // expected-note 3{{where 'A' = 'K'}} // Same as S2, but without the Q requirement. struct S3: P2 {} -typealias R3 = S3 // expected-note {{where 'A' = 'K'}} expected-note {{where 'A' = 'K'}} +typealias R3 = S3 // expected-note 2{{where 'A' = 'K'}} func foo(_ y: T.A.Type) -> T {} let _ = foo(K.self) as S2 // expected-error {{generic struct 'S2' requires that 'K' conform to 'Q'}} @@ -38,11 +36,8 @@ let _ = foo(K.self) as R2 // expected-error {{generic type alias 'R2' re let _ = foo(K.self) as R3 // expected-error {{generic type alias 'R3' requires that 'K' conform to 'Q'}} let _: S2 = foo(K.self) // expected-error {{generic struct 'S2' requires that 'K' conform to 'Q'}} -// FIXME: We ought to be able to infer 'U' here. -let _: R2 = foo(K.self) // expected-error 2{{generic type alias 'R2' requires that 'K' conform to 'Q'}} -// expected-error@-1 2 {{generic parameter 'U' could not be inferred}} -let _: R3 = foo(K.self) // expected-error {{generic type alias 'R3' requires that 'K' conform to 'Q'}} -// expected-error@-1 2 {{generic parameter 'U' could not be inferred}} +let _: R2 = foo(K.self) // expected-error {{generic type alias 'R2' requires that 'K' conform to 'Q'}} +let _: R3 = foo(K.self) // expected-error {{generic type alias 'R3' requires that 'K' conform to 'Q'}} func foo(_ x: T.Type, _ y: T.A.Type) {} foo(S2<_>.self, K.self) // expected-error {{generic struct 'S2' requires that 'K' conform to 'Q'}} @@ -53,3 +48,17 @@ struct S4 { // expected-note {{where 'T' = 'Int'}} } _ = S4<_>(0) // expected-error {{generic struct 'S4' requires that 'Int' conform to 'Q'}} + +func testLocalOuterGeneric(_ x: T) { + typealias X = (T, U) // expected-note {{where 'U' = 'String'}} + let _: X<_> = (x, "") // expected-error {{generic type alias 'X' requires that 'String' conform to 'Q'}} + let _: X<_> = (x, ConformingType()) +} + +struct TestParentGeneric { + typealias X = (T, U) // expected-note {{where 'U' = 'String'}} + func bar(_ x: T) { + let _: X<_> = (x, "") // expected-error {{generic type alias 'X' requires that 'String' conform to 'Q'}} + let _: X<_> = (x, ConformingType()) + } +}