mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Basic Sema support for covariant collection casting.
This commit is contained in:
@@ -143,6 +143,9 @@ namespace swift {
|
||||
/// \brief Enable experimental nested generic types feature.
|
||||
bool EnableExperimentalNestedGenericTypes = false;
|
||||
|
||||
/// \brief Enable generalized collection casting.
|
||||
bool EnableExperimentalCollectionCasts = false;
|
||||
|
||||
/// Should we check the target OSs of serialized modules to see that they're
|
||||
/// new enough?
|
||||
bool EnableTargetOSChecking = true;
|
||||
|
||||
@@ -230,6 +230,10 @@ def enable_experimental_nested_generic_types :
|
||||
Flag<["-"], "enable-experimental-nested-generic-types">,
|
||||
HelpText<"Enable experimental support for nested generic types">;
|
||||
|
||||
def enable_experimental_collection_casts :
|
||||
Flag<["-"], "enable-experimental-collection-casts">,
|
||||
HelpText<"Enable experimental support for general collection casting">;
|
||||
|
||||
def disable_availability_checking : Flag<["-"],
|
||||
"disable-availability-checking">,
|
||||
HelpText<"Disable checking for potentially unavailable APIs">;
|
||||
|
||||
@@ -743,6 +743,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
||||
Opts.EnableExperimentalNestedGenericTypes |=
|
||||
Args.hasArg(OPT_enable_experimental_nested_generic_types);
|
||||
|
||||
Opts.EnableExperimentalCollectionCasts |=
|
||||
Args.hasArg(OPT_enable_experimental_collection_casts);
|
||||
|
||||
Opts.DisableAvailabilityChecking |=
|
||||
Args.hasArg(OPT_disable_availability_checking);
|
||||
|
||||
|
||||
@@ -3820,6 +3820,15 @@ ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restric
|
||||
Type baseType1 = getBaseTypeForArrayType(t1);
|
||||
Type baseType2 = getBaseTypeForArrayType(t2);
|
||||
|
||||
if (TC.getLangOpts().EnableExperimentalCollectionCasts) {
|
||||
return matchTypes(baseType1,
|
||||
baseType2,
|
||||
matchKind,
|
||||
subFlags,
|
||||
locator.withPathElement(
|
||||
ConstraintLocator::PathElement::getGenericArgument(0)));
|
||||
}
|
||||
|
||||
// Look through type variables in the first element type; we need to know
|
||||
// it's structure before we can decide whether this can be an array upcast.
|
||||
TypeVariableType *baseTypeVar1;
|
||||
@@ -3873,6 +3882,29 @@ ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restric
|
||||
Type key2, value2;
|
||||
std::tie(key2, value2) = *isDictionaryType(t2);
|
||||
|
||||
if (TC.getLangOpts().EnableExperimentalCollectionCasts) {
|
||||
// The source key and value types must be subtypes of the destination
|
||||
// key and value types, respectively.
|
||||
auto result = matchTypes(key1, key2, matchKind, subFlags,
|
||||
locator.withPathElement(
|
||||
ConstraintLocator::PathElement::getGenericArgument(0)));
|
||||
if (result == SolutionKind::Error)
|
||||
return result;
|
||||
|
||||
switch (matchTypes(value1, value2, matchKind, subFlags,
|
||||
locator.withPathElement(
|
||||
ConstraintLocator::PathElement::getGenericArgument(1)))) {
|
||||
case SolutionKind::Solved:
|
||||
return result;
|
||||
|
||||
case SolutionKind::Unsolved:
|
||||
return SolutionKind::Unsolved;
|
||||
|
||||
case SolutionKind::Error:
|
||||
return SolutionKind::Error;
|
||||
}
|
||||
}
|
||||
|
||||
// Look through type variables in the first key and value type; we
|
||||
// need to know their structure before we can decide whether this
|
||||
// can be an upcast.
|
||||
@@ -3979,6 +4011,15 @@ ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restric
|
||||
auto t2 = type2->getDesugaredType();
|
||||
Type baseType2 = getBaseTypeForSetType(t2);
|
||||
|
||||
if (TC.getLangOpts().EnableExperimentalCollectionCasts) {
|
||||
return matchTypes(baseType1,
|
||||
baseType2,
|
||||
matchKind,
|
||||
subFlags,
|
||||
locator.withPathElement(
|
||||
ConstraintLocator::PathElement::getGenericArgument(0)));
|
||||
}
|
||||
|
||||
// Look through type variables in the first base type; we need to know
|
||||
// their structure before we can decide whether this can be an upcast.
|
||||
TypeVariableType *baseTypeVar1 = nullptr;
|
||||
|
||||
42
test/SILGen/collection_subtype_downcast.swift
Normal file
42
test/SILGen/collection_subtype_downcast.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
// RUN: %target-swift-frontend -enable-experimental-collection-casts -emit-silgen -sdk %S/Inputs %s | FileCheck %s
|
||||
|
||||
struct S { var x, y: Int }
|
||||
|
||||
// CHECK-LABEL: sil hidden @_TF27collection_subtype_downcast14array_downcastFT5arrayGSaP___GSqGSaVS_1S__ :
|
||||
// CHECK: bb0(%0 : $Array<protocol<>>):
|
||||
// CHECK-NEXT: debug_value %0
|
||||
// CHECK-NEXT: retain_value %0
|
||||
// CHECK-NEXT: // function_ref
|
||||
// CHECK-NEXT: [[FN:%.*]] = function_ref @_TFs21_arrayConditionalCastu0_rFGSax_GSqGSaq___
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<protocol<>, S>(%0) : $@convention(thin) <τ_0_0, τ_0_1> (@owned Array<τ_0_0>) -> @owned Optional<Array<τ_0_1>>
|
||||
// CHECK-NEXT: release_value %0
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
func array_downcast(array: [Any]) -> [S]? {
|
||||
return array as? [S]
|
||||
}
|
||||
|
||||
extension S : Hashable {
|
||||
var hashValue : Int {
|
||||
return x + y
|
||||
}
|
||||
}
|
||||
func ==(lhs: S, rhs: S) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// FIXME: This entrypoint name should not be bridging-specific
|
||||
// CHECK-LABEL: sil hidden @_TF27collection_subtype_downcast13dict_downcastFT4dictGVs10DictionaryVS_1SP___GSqGS0_S1_Si__ :
|
||||
// CHECK: bb0(%0 : $Dictionary<S, protocol<>>):
|
||||
// CHECK-NEXT: debug_value %0
|
||||
// CHECK-NEXT: retain_value %0
|
||||
// CHECK-NEXT: // function_ref
|
||||
// CHECK-NEXT: [[FN:%.*]] = function_ref @_TFs42_dictionaryBridgeFromObjectiveCConditionalu2_Rxs8Hashable0_S_rFGVs10Dictionaryxq__GSqGS0_q0_q1___
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<S, protocol<>, S, Int>(%0) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@owned Dictionary<τ_0_0, τ_0_1>) -> @owned Optional<Dictionary<τ_0_2, τ_0_3>>
|
||||
// CHECK-NEXT: release_value %0
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
func dict_downcast(dict: [S: Any]) -> [S: Int]? {
|
||||
return dict as? [S: Int]
|
||||
}
|
||||
|
||||
// It's not actually possible to test this for Sets independent of
|
||||
// the bridging rules.
|
||||
42
test/SILGen/collection_subtype_upcast.swift
Normal file
42
test/SILGen/collection_subtype_upcast.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
// RUN: %target-swift-frontend -enable-experimental-collection-casts -emit-silgen -sdk %S/Inputs %s | FileCheck %s
|
||||
|
||||
struct S { var x, y: Int }
|
||||
|
||||
// CHECK-LABEL: sil hidden @_TF25collection_subtype_upcast12array_upcastFT5arrayGSaVS_1S__GSaP__ :
|
||||
// CHECK: bb0(%0 : $Array<S>):
|
||||
// CHECK-NEXT: debug_value %0
|
||||
// CHECK-NEXT: retain_value %0
|
||||
// CHECK-NEXT: // function_ref
|
||||
// CHECK-NEXT: [[FN:%.*]] = function_ref @_TFs15_arrayForceCastu0_rFGSax_GSaq__
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<S, protocol<>>(%0) : $@convention(thin) <τ_0_0, τ_0_1> (@owned Array<τ_0_0>) -> @owned Array<τ_0_1>
|
||||
// CHECK-NEXT: release_value %0
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
func array_upcast(array: [S]) -> [Any] {
|
||||
return array
|
||||
}
|
||||
|
||||
extension S : Hashable {
|
||||
var hashValue : Int {
|
||||
return x + y
|
||||
}
|
||||
}
|
||||
func ==(lhs: S, rhs: S) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// FIXME: This entrypoint name should not be bridging-specific
|
||||
// CHECK-LABEL: sil hidden @_TF25collection_subtype_upcast11dict_upcastFT4dictGVs10DictionaryVS_1SSi__GS0_S1_P__ :
|
||||
// CHECK: bb0(%0 : $Dictionary<S, Int>):
|
||||
// CHECK-NEXT: debug_value %0
|
||||
// CHECK-NEXT: retain_value %0
|
||||
// CHECK-NEXT: // function_ref
|
||||
// CHECK-NEXT: [[FN:%.*]] = function_ref @_TFs29_dictionaryBridgeToObjectiveCu2_Rxs8Hashable0_S_rFGVs10Dictionaryxq__GS0_q0_q1__
|
||||
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<S, Int, S, protocol<>>(%0) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@owned Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
|
||||
// CHECK-NEXT: release_value %0
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
func dict_upcast(dict: [S: Int]) -> [S: Any] {
|
||||
return dict
|
||||
}
|
||||
|
||||
// It's not actually possible to test this for Sets independent of
|
||||
// the bridging rules.
|
||||
@@ -48,6 +48,7 @@ var aa: [[A]] = []
|
||||
var bb: [[B]] = []
|
||||
|
||||
aa = bb // expected-error {{cannot assign value of type '[[B]]' to type '[[A]]'}}
|
||||
bb = aa // expected-error {{cannot assign value of type '[[A]]' to type '[[B]]'}}
|
||||
|
||||
class C {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user