Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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);
}
Expand Down
26 changes: 20 additions & 6 deletions lib/Sema/TypeOfReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<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()));
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) {
Expand Down
24 changes: 24 additions & 0 deletions test/Constraints/rdar160135085.swift
Original file line number Diff line number Diff line change
@@ -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<T> {
public init(_ x: T) {}
}

//--- b.swift

import A
public typealias S = A.S

//--- c.swift

import A
import B

_ = S(0)
36 changes: 23 additions & 13 deletions test/Constraints/requirement_opening.swift
Original file line number Diff line number Diff line change
@@ -1,47 +1,43 @@
// RUN: %target-typecheck-verify-swift

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 {
associatedtype A
}

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'}}
let _ = foo(K<Int>.self) as R2<K> // expected-error {{generic type alias 'R2' requires that 'K<Int>' conform to 'Q'}}
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'}}
Expand All @@ -52,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())
}
}
16 changes: 16 additions & 0 deletions test/decl/typealias/generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -465,3 +465,19 @@ func testSugar(_ gx: GX<Int>, _ gy: GX<Int>.GY<Double>, gz: GX<Int>.GY<Double>.E
let i2: Int = gy // expected-error{{cannot convert value of type 'GX<Int>.GY<Double>' (aka 'Array<Double>') to specified type 'Int'}}
let i3: Int = gz // expected-error{{cannot convert value of type 'GX<Int>.GY<Double>.Element' (aka 'Double') to specified type 'Int'}}
}

func testLocalRequirementInference<T>(_ x: T, y: Int, s: S) {
typealias X<U: P> = (T, U) where T == U.A
func foo<V>(_ x: X<V>) {} // 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<T> {
typealias X<U: P> = (T, U) where T == U.A
func foo<V>(_ x: X<V>) {} // 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}}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// {"kind":"typecheck","signature":"swift::constraints::ConstraintSystem::openGenericParameters(swift::DeclContext*, swift::GenericSignature, llvm::SmallVectorImpl<std::__1::pair<swift::GenericTypeParamType*, swift::TypeVariableType*>>&, swift::constraints::ConstraintLocatorBuilder, swift::constraints::PreparedOverloadBuilder*)","signatureAssert":"Assertion failed: (sig), function openGenericParameters"}
// RUN: not %target-swift-frontend -typecheck %s
class a<b
func c -> d
typealias c : a
c
Original file line number Diff line number Diff line change
@@ -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<each b {
typealias d<c> = (
> func 1 {
typealias e = f
e
typealias e = d