mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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
This commit is contained in:
@@ -2345,7 +2345,11 @@ public:
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -261,14 +261,30 @@ public:
|
||||
}
|
||||
|
||||
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<Type, 4> 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) {
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
// REQUIRES: rdar160135085
|
||||
|
||||
struct K<U> {} // expected-note 6{{'U' declared as parameter to type 'K'}}
|
||||
struct K<U> {}
|
||||
protocol Q {}
|
||||
struct ConformingType: Q {}
|
||||
|
||||
struct S1<T: Q>: ExpressibleByArrayLiteral { // expected-note 2{{where 'T' = 'K<Int>'}}
|
||||
init(_ x: T) {}
|
||||
init(arrayLiteral: T...) {}
|
||||
}
|
||||
|
||||
typealias R1<T: Q> = S1<T> // expected-note {{where 'T' = 'K<Int>'}} expected-note 2{{where 'T' = 'K<U>'}}
|
||||
typealias R1<T: Q> = S1<T> // expected-note 2{{where 'T' = 'K<Int>'}}
|
||||
|
||||
func foo(_ x: K<Int>) {
|
||||
let _ = [x] as S1<K> // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
|
||||
let _ = [x] as R1<K> // expected-error {{generic type alias 'R1' requires that 'K<Int>' conform to 'Q'}}
|
||||
|
||||
let _: S1<K> = [x] // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
|
||||
// FIXME: We ought to be able to infer 'U' here.
|
||||
let _: R1<K> = [x] // expected-error 2 {{generic type alias 'R1' requires that 'K<U>' conform to 'Q'}}
|
||||
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
|
||||
let _: S1<K> = [x] // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
|
||||
let _: R1<K> = [x] // expected-error {{generic type alias 'R1' requires that 'K<Int>' conform to 'Q'}}
|
||||
}
|
||||
|
||||
protocol P2 {
|
||||
@@ -26,11 +24,11 @@ protocol P2 {
|
||||
}
|
||||
|
||||
struct S2<A: Q>: P2 {} // expected-note 3{{where 'A' = 'K<Int>'}}
|
||||
typealias R2<A: Q> = S2<A> // expected-note 2{{where 'A' = 'K<Int>'}} expected-note 2{{where 'A' = 'K<U>'}}
|
||||
typealias R2<A: Q> = S2<A> // expected-note 3{{where 'A' = 'K<Int>'}}
|
||||
|
||||
// Same as S2, but without the Q requirement.
|
||||
struct S3<A>: P2 {}
|
||||
typealias R3<A: Q> = S3<A> // expected-note {{where 'A' = 'K<Int>'}} expected-note {{where 'A' = 'K<U>'}}
|
||||
typealias R3<A: Q> = S3<A> // expected-note 2{{where 'A' = 'K<Int>'}}
|
||||
|
||||
func foo<T: P2>(_ y: T.A.Type) -> T {}
|
||||
let _ = foo(K<Int>.self) as S2<K> // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
|
||||
@@ -38,11 +36,8 @@ let _ = foo(K<Int>.self) as R2<K> // expected-error {{generic type alias 'R2' re
|
||||
let _ = foo(K<Int>.self) as R3<K> // expected-error {{generic type alias 'R3' requires that 'K<Int>' conform to 'Q'}}
|
||||
|
||||
let _: S2<K> = foo(K<Int>.self) // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
|
||||
// FIXME: We ought to be able to infer 'U' here.
|
||||
let _: R2<K> = foo(K<Int>.self) // expected-error 2{{generic type alias 'R2' requires that 'K<U>' conform to 'Q'}}
|
||||
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
|
||||
let _: R3<K> = foo(K<Int>.self) // expected-error {{generic type alias 'R3' requires that 'K<U>' conform to 'Q'}}
|
||||
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
|
||||
let _: R2<K> = foo(K<Int>.self) // expected-error {{generic type alias 'R2' requires that 'K<Int>' conform to 'Q'}}
|
||||
let _: R3<K> = foo(K<Int>.self) // expected-error {{generic type alias 'R3' requires that 'K<Int>' conform to 'Q'}}
|
||||
|
||||
func foo<T: P2>(_ x: T.Type, _ y: T.A.Type) {}
|
||||
foo(S2<_>.self, K<Int>.self) // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
|
||||
@@ -53,3 +48,17 @@ struct S4<T: Q> { // expected-note {{where 'T' = 'Int'}}
|
||||
}
|
||||
|
||||
_ = S4<_>(0) // expected-error {{generic struct 'S4' requires that 'Int' conform to 'Q'}}
|
||||
|
||||
func testLocalOuterGeneric<T>(_ x: T) {
|
||||
typealias X<U: Q> = (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<T> {
|
||||
typealias X<U: Q> = (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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user