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 9f085732503e2..463ad2c16ae74 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -261,16 +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())); - openGenericTypeRequirements(substTy->getDecl(), - substTy->getSubstitutionMap()); - return substTy; + 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/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..1fcc27e7db37a 100644 --- a/test/Constraints/requirement_opening.swift +++ b/test/Constraints/requirement_opening.swift @@ -1,23 +1,22 @@ // RUN: %target-typecheck-verify-swift -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 { @@ -25,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'}} @@ -37,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'}} @@ -52,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()) + } +} 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