mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Runtime] Handle tuple/tuple dynamic casts that add/remove labels.
Introduce narrow support for tuple/tuple dynamic casts that merely add or remove labels, but require the element types to match exactly. This gets us back to allowing the same correct dynamic casts as in Swift 3.0, when labels were completely ignored.
This commit is contained in:
@@ -2497,6 +2497,51 @@ static bool _dynamicCastStructToStruct(OpaqueValue *destination,
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool _dynamicCastTupleToTuple(OpaqueValue *destination,
|
||||
OpaqueValue *source,
|
||||
const TupleTypeMetadata *sourceType,
|
||||
const TupleTypeMetadata *targetType,
|
||||
DynamicCastFlags flags) {
|
||||
assert(sourceType != targetType &&
|
||||
"Caller should handle exact tuple matches");
|
||||
|
||||
|
||||
// Simple case: number of elements mismatches.
|
||||
if (sourceType->NumElements != targetType->NumElements)
|
||||
return _fail(source, sourceType, targetType, flags);
|
||||
|
||||
// Check that the elements line up.
|
||||
const char *sourceLabels = sourceType->Labels;
|
||||
const char *targetLabels = targetType->Labels;
|
||||
for (unsigned i = 0, n = sourceType->NumElements; i != n; ++i) {
|
||||
// Check the label, if there is one.
|
||||
if (sourceLabels && targetLabels && sourceLabels != targetLabels) {
|
||||
const char *sourceSpace = strchr(sourceLabels, ' ');
|
||||
const char *targetSpace = strchr(targetLabels, ' ');
|
||||
|
||||
// If both have labels, and the labels mismatch, we fail.
|
||||
if (sourceSpace && sourceSpace != sourceLabels &&
|
||||
targetSpace && targetSpace != targetLabels) {
|
||||
unsigned sourceLen = sourceSpace - sourceLabels;
|
||||
unsigned targetLen = targetSpace - targetLabels;
|
||||
if (sourceLen != targetLen ||
|
||||
strncmp(sourceLabels, targetLabels, sourceLen) != 0)
|
||||
return _fail(source, sourceType, targetType, flags);
|
||||
}
|
||||
|
||||
sourceLabels = sourceSpace ? sourceSpace + 1 : nullptr;
|
||||
targetLabels = targetSpace ? targetSpace + 1 : nullptr;
|
||||
}
|
||||
|
||||
// Make sure the types match exactly.
|
||||
// FIXME: we should dynamically cast the elements themselves.
|
||||
if (sourceType->getElement(i).Type != targetType->getElement(i).Type)
|
||||
return _fail(source, sourceType, targetType, flags);
|
||||
}
|
||||
|
||||
return _succeed(destination, source, targetType, flags);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/****************************** Main Entrypoint *******************************/
|
||||
/******************************************************************************/
|
||||
@@ -2718,6 +2763,15 @@ bool swift::swift_dynamicCast(OpaqueValue *dest,
|
||||
targetType, flags);
|
||||
}
|
||||
|
||||
// If both are tuple types, allow the cast to add/remove labels.
|
||||
if (srcType->getKind() == MetadataKind::Tuple &&
|
||||
targetType->getKind() == MetadataKind::Tuple) {
|
||||
return _dynamicCastTupleToTuple(dest, src,
|
||||
cast<TupleTypeMetadata>(srcType),
|
||||
cast<TupleTypeMetadata>(targetType),
|
||||
flags);
|
||||
}
|
||||
|
||||
// Otherwise, we have a failure.
|
||||
return _fail(src, srcType, targetType, flags);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user