Fixes for typealiases involving generics (#3811)
* Serialization: Another fix for generic typealiases
Fixes <https://bugs.swift.org/browse/SR-1889>.
* Sema: Fix FindCapturedVars to look through typealiases
Fixes <https://bugs.swift.org/browse/SR-1781>.
diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp
index ed54ffc..ce4bce4 100644
--- a/lib/Sema/TypeCheckCaptures.cpp
+++ b/lib/Sema/TypeCheckCaptures.cpp
@@ -73,6 +73,9 @@
if (!type)
return;
+ // We want to look through type aliases here.
+ type = type->getCanonicalType();
+
// If the type contains dynamic 'Self', conservatively assume we will
// need 'Self' metadata at runtime. We could generalize the analysis
// used below for usages of generic parameters in Objective-C
@@ -95,42 +98,22 @@
});
}
- // Nothing to do if the type is concrete.
- if (!type->hasArchetype())
- return;
-
- // Walk the type to see if we have any archetypes that are *not* open
- // existentials and that aren't type-erased.
- class CapturesTypeWalker final : public TypeWalker {
- SourceLoc &GenericParamCaptureLoc;
- SourceLoc CurLoc;
-
- public:
- CapturesTypeWalker(SourceLoc &GenericParamCaptureLoc,
- SourceLoc curLoc)
- : GenericParamCaptureLoc(GenericParamCaptureLoc),
- CurLoc(curLoc) {}
-
- Action walkToTypePre(Type t) override {
- // Similar to dynamic 'Self', IRGen doesn't really need type metadata
- // for class-bound archetypes in nearly as many cases as with opaque
- // archetypes.
- //
- // Perhaps this entire analysis should happen at the SILGen level,
- // instead, but even there we don't really have enough information to
- // perform it accurately.
- if (t->is<ArchetypeType>() && !t->isOpenedExistential()) {
- if (GenericParamCaptureLoc.isInvalid())
- GenericParamCaptureLoc = CurLoc;
- return Action::Continue;
+ // Similar to dynamic 'Self', IRGen doesn't really need type metadata
+ // for class-bound archetypes in nearly as many cases as with opaque
+ // archetypes.
+ //
+ // Perhaps this entire analysis should happen at the SILGen level,
+ // instead, but even there we don't really have enough information to
+ // perform it accurately.
+ if (type->hasArchetype()) {
+ type.visit([&](Type t) {
+ if (t->is<ArchetypeType>() &&
+ !t->isOpenedExistential() &&
+ GenericParamCaptureLoc.isInvalid()) {
+ GenericParamCaptureLoc = loc;
}
-
- return Action::Continue;
- }
- };
-
- type.walk(CapturesTypeWalker(GenericParamCaptureLoc,
- loc));
+ });
+ }
}
/// Add the specified capture to the closure's capture list, diagnosing it
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index ea042aa..fd940de 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1359,6 +1359,8 @@
// Simple case: use the nominal type's generic parameters.
paramList = nominal->getGenericParams();
}
+ } else if (auto alias = dyn_cast<TypeAliasDecl>(base)) {
+ paramList = alias->getGenericParams();
} else if (auto fn = dyn_cast<AbstractFunctionDecl>(base))
paramList = fn->getGenericParams();
diff --git a/test/expr/capture/generic_params.swift b/test/expr/capture/generic_params.swift
index 7767fa8..d96c563 100644
--- a/test/expr/capture/generic_params.swift
+++ b/test/expr/capture/generic_params.swift
@@ -22,4 +22,13 @@
// they're not mentioned in the function body
// CHECK: func_decl "innerGeneric(u:)"<U> type='<U> (u: U) -> ()' {{.*}} captures=(<generic> )
func innerGeneric<U>(u: U) {}
+
+ // Make sure we look through typealiases
+ typealias TT = (a: T, b: T)
+
+ // CHECK: func_decl "localFunction(tt:)" type='<T> (tt: TT) -> ()' {{.*}} captures=(<generic> )
+ func localFunction(tt: TT) {}
+
+ // CHECK: closure_expr type='(TT) -> ()' {{.*}} captures=(<generic> )
+ let _: (TT) -> () = { _ in }
}
diff --git a/test/multifile/typealias/one-module/library.swift b/test/multifile/typealias/one-module/library.swift
new file mode 100644
index 0000000..7785da5
--- /dev/null
+++ b/test/multifile/typealias/one-module/library.swift
@@ -0,0 +1,9 @@
+// RUN: true
+
+public enum Result<T, U>
+{
+ case success(T)
+ case failure(U)
+}
+
+public typealias GenericResult<T> = Result<T, Error>
diff --git a/test/multifile/typealias/one-module/main.swift b/test/multifile/typealias/one-module/main.swift
new file mode 100644
index 0000000..445a12a
--- /dev/null
+++ b/test/multifile/typealias/one-module/main.swift
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t && mkdir %t
+
+// RUN: %target-build-swift %S/main.swift %S/library.swift
+// RUN: %target-build-swift -g %S/main.swift %S/library.swift
+
+// REQUIRES: executable_test
+
+func testFunction<T>(withCompletion completion: (Result<T, Error>) -> Void) { }
+testFunction { (result: GenericResult<Int>) in }
diff --git a/test/multifile/typealias/two-modules/main.swift b/test/multifile/typealias/two-modules/main.swift
index 7b58d1c..6f600cb 100644
--- a/test/multifile/typealias/two-modules/main.swift
+++ b/test/multifile/typealias/two-modules/main.swift
@@ -5,6 +5,10 @@
// RUN: %target-build-swift -emit-library -c %S/library.swift -o %t/linker/library.o
// RUN: %target-build-swift %S/main.swift %t/linker/library.o -I %t/linker/ -L %t/linker/ -o %t/linker/main
+// RUN: %target-build-swift -g -emit-module -c %S/library.swift -o %t/linker/library.o
+// RUN: %target-build-swift -g -emit-library -c %S/library.swift -o %t/linker/library.o
+// RUN: %target-build-swift -g %S/main.swift %t/linker/library.o -I %t/linker/ -L %t/linker/ -o %t/linker/main
+
// REQUIRES: executable_test
import library