mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Begin adding plumbing for the type checker to accept "forward" bridged array conversions. (rdar://problem/16540403)
Swift SVN r17640
This commit is contained in:
@@ -372,6 +372,9 @@ public:
|
|||||||
|
|
||||||
/// Retrieve the simple upcast conversion function for Array<T>.
|
/// Retrieve the simple upcast conversion function for Array<T>.
|
||||||
FuncDecl *getArrayUpCast(LazyResolver *resolver) const;
|
FuncDecl *getArrayUpCast(LazyResolver *resolver) const;
|
||||||
|
|
||||||
|
/// Retrieve the simple bridge conversion function for Array<T>.
|
||||||
|
FuncDecl *getArrayBridgeToObjectiveC(LazyResolver *resolver) const;
|
||||||
|
|
||||||
/// Retrieve the declaration of
|
/// Retrieve the declaration of
|
||||||
/// Swift._does{,ImplicitlyUnwrapped}OptionalHaveValue.
|
/// Swift._does{,ImplicitlyUnwrapped}OptionalHaveValue.
|
||||||
@@ -592,6 +595,10 @@ public:
|
|||||||
|
|
||||||
/// Returns the protocol requirement decls for a conforming decl.
|
/// Returns the protocol requirement decls for a conforming decl.
|
||||||
ArrayRef<ValueDecl *> getConformances(const ValueDecl *D);
|
ArrayRef<ValueDecl *> getConformances(const ValueDecl *D);
|
||||||
|
|
||||||
|
/// \brief Retrieve the substitutions for a bound generic type, if known.
|
||||||
|
Optional<ArrayRef<Substitution>>
|
||||||
|
getSubstitutions(BoundGenericType *Bound) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Decl;
|
friend class Decl;
|
||||||
@@ -603,10 +610,6 @@ private:
|
|||||||
|
|
||||||
friend class BoundGenericType;
|
friend class BoundGenericType;
|
||||||
|
|
||||||
/// \brief Retrieve the substitutions for a bound generic type, if known.
|
|
||||||
Optional<ArrayRef<Substitution>>
|
|
||||||
getSubstitutions(BoundGenericType *Bound) const;
|
|
||||||
|
|
||||||
/// \brief Set the substitutions for the given bound generic type.
|
/// \brief Set the substitutions for the given bound generic type.
|
||||||
void setSubstitutions(BoundGenericType *Bound,
|
void setSubstitutions(BoundGenericType *Bound,
|
||||||
ArrayRef<Substitution> Subs) const;
|
ArrayRef<Substitution> Subs) const;
|
||||||
|
|||||||
@@ -2041,6 +2041,23 @@ public:
|
|||||||
return E->getKind() == ExprKind::ArrayUpcastConversion;
|
return E->getKind() == ExprKind::ArrayUpcastConversion;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ArrayBridgedConversionExpr - Convert an Array<U> to an Array<T>, where
|
||||||
|
// T is bridged to U.
|
||||||
|
class ArrayBridgedConversionExpr : public ImplicitConversionExpr {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Keep track of whether or not the type being bridged to conforms to the
|
||||||
|
/// _ConditionallyBridgedToObjectiveC protocol.
|
||||||
|
bool isConditionallyBridged = false;
|
||||||
|
|
||||||
|
ArrayBridgedConversionExpr(Expr *subExpr, Type type)
|
||||||
|
: ImplicitConversionExpr(ExprKind::ArrayBridgedConversion, subExpr, type) {}
|
||||||
|
|
||||||
|
static bool classof(const Expr *E) {
|
||||||
|
return E->getKind() == ExprKind::ArrayBridgedConversion;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// AnyErasureExpr - An abstract class for implicit conversions that
|
/// AnyErasureExpr - An abstract class for implicit conversions that
|
||||||
/// erase a type into an existential in some way.
|
/// erase a type into an existential in some way.
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ ABSTRACT_EXPR(ImplicitConversion, Expr)
|
|||||||
EXPR(CovariantReturnConversion, ImplicitConversionExpr)
|
EXPR(CovariantReturnConversion, ImplicitConversionExpr)
|
||||||
EXPR(MetatypeConversion, ImplicitConversionExpr)
|
EXPR(MetatypeConversion, ImplicitConversionExpr)
|
||||||
EXPR(ArrayUpcastConversion, ImplicitConversionExpr)
|
EXPR(ArrayUpcastConversion, ImplicitConversionExpr)
|
||||||
|
EXPR(ArrayBridgedConversion, ImplicitConversionExpr)
|
||||||
ABSTRACT_EXPR(AnyErasure, ImplicitConversionExpr)
|
ABSTRACT_EXPR(AnyErasure, ImplicitConversionExpr)
|
||||||
EXPR(Erasure, AnyErasureExpr)
|
EXPR(Erasure, AnyErasureExpr)
|
||||||
EXPR(MetatypeErasure, AnyErasureExpr)
|
EXPR(MetatypeErasure, AnyErasureExpr)
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ struct ASTContext::Implementation {
|
|||||||
|
|
||||||
/// Array<T> simple upcast.
|
/// Array<T> simple upcast.
|
||||||
FuncDecl *GetArrayUpCast = nullptr;
|
FuncDecl *GetArrayUpCast = nullptr;
|
||||||
|
|
||||||
|
/// Array<T> bridge conversion.
|
||||||
|
FuncDecl *GetArrayBridgeToObjectiveC = nullptr;
|
||||||
|
|
||||||
/// func _doesOptionalHaveValue<T>(v : [inout] Optional<T>) -> T
|
/// func _doesOptionalHaveValue<T>(v : [inout] Optional<T>) -> T
|
||||||
FuncDecl *DoesOptionalHaveValueDecls[NumOptionalTypeKinds] = {};
|
FuncDecl *DoesOptionalHaveValueDecls[NumOptionalTypeKinds] = {};
|
||||||
@@ -629,6 +632,20 @@ FuncDecl *ASTContext::getArrayUpCast(LazyResolver *resolver) const {
|
|||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FuncDecl *ASTContext::getArrayBridgeToObjectiveC(LazyResolver *resolver) const {
|
||||||
|
auto &cache = Impl.GetArrayBridgeToObjectiveC;
|
||||||
|
if (cache) return cache;
|
||||||
|
|
||||||
|
// Look for a generic function.
|
||||||
|
CanType input, output, param;
|
||||||
|
auto decl = findLibraryIntrinsic(*this, "_arrayBridgeToObjectiveC", resolver);
|
||||||
|
if (!decl)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
cache = decl;
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
/// Check whether the given type is Optional applied to the given
|
/// Check whether the given type is Optional applied to the given
|
||||||
/// type argument.
|
/// type argument.
|
||||||
static bool isOptionalType(const ASTContext &ctx,
|
static bool isOptionalType(const ASTContext &ctx,
|
||||||
|
|||||||
@@ -1361,6 +1361,11 @@ public:
|
|||||||
printRec(E->getSubExpr());
|
printRec(E->getSubExpr());
|
||||||
OS << ')';
|
OS << ')';
|
||||||
}
|
}
|
||||||
|
void visitArrayBridgedConversionExpr(ArrayBridgedConversionExpr *E) {
|
||||||
|
printCommon(E, "array_bridged_conversion_expr") << '\n';
|
||||||
|
printRec(E->getSubExpr());
|
||||||
|
OS << ')';
|
||||||
|
}
|
||||||
void visitDerivedToBaseExpr(DerivedToBaseExpr *E) {
|
void visitDerivedToBaseExpr(DerivedToBaseExpr *E) {
|
||||||
printCommon(E, "derived_to_base_expr") << '\n';
|
printCommon(E, "derived_to_base_expr") << '\n';
|
||||||
printRec(E->getSubExpr());
|
printRec(E->getSubExpr());
|
||||||
|
|||||||
@@ -745,6 +745,11 @@ struct ASTNodeBase {};
|
|||||||
verifyChecked(E->getSubExpr());
|
verifyChecked(E->getSubExpr());
|
||||||
verifyCheckedBase(E);
|
verifyCheckedBase(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void verifyChecked(ArrayBridgedConversionExpr *E) {
|
||||||
|
verifyChecked(E->getSubExpr());
|
||||||
|
verifyCheckedBase(E);
|
||||||
|
}
|
||||||
|
|
||||||
void verifyChecked(DerivedToBaseExpr *E) {
|
void verifyChecked(DerivedToBaseExpr *E) {
|
||||||
PrettyStackTraceExpr debugStack(Ctx, "verifying DerivedToBaseExpr", E);
|
PrettyStackTraceExpr debugStack(Ctx, "verifying DerivedToBaseExpr", E);
|
||||||
|
|||||||
@@ -177,6 +177,8 @@ namespace {
|
|||||||
SGFContext C);
|
SGFContext C);
|
||||||
RValue visitArrayUpcastConversionExpr(ArrayUpcastConversionExpr *E,
|
RValue visitArrayUpcastConversionExpr(ArrayUpcastConversionExpr *E,
|
||||||
SGFContext C);
|
SGFContext C);
|
||||||
|
RValue visitArrayBridgedConversionExpr(ArrayBridgedConversionExpr *E,
|
||||||
|
SGFContext C);
|
||||||
RValue visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E, SGFContext C);
|
RValue visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E, SGFContext C);
|
||||||
RValue visitFunctionConversionExpr(FunctionConversionExpr *E,
|
RValue visitFunctionConversionExpr(FunctionConversionExpr *E,
|
||||||
SGFContext C);
|
SGFContext C);
|
||||||
@@ -947,6 +949,84 @@ visitArrayUpcastConversionExpr(ArrayUpcastConversionExpr *E,
|
|||||||
return RValue(SGF, E, emitApply);
|
return RValue(SGF, E, emitApply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RValue RValueEmitter::
|
||||||
|
visitArrayBridgedConversionExpr(ArrayBridgedConversionExpr *E,
|
||||||
|
SGFContext C) {
|
||||||
|
|
||||||
|
SILLocation loc = RegularLocation(E);
|
||||||
|
|
||||||
|
// Get the sub expression argument as a managed value
|
||||||
|
auto mv = SGF.emitRValueAsSingleValue(E->getSubExpr());
|
||||||
|
|
||||||
|
// Compute substitutions for the intrinsic call.
|
||||||
|
auto canTypeT = E->getSubExpr()->getType().getPointer()->getCanonicalType();
|
||||||
|
auto canTypeU = E->getType().getPointer()->getCanonicalType();
|
||||||
|
auto arrayT = cast<BoundGenericStructType>(canTypeT)->getGenericArgs()[0];
|
||||||
|
auto arrayU = cast<BoundGenericStructType>(canTypeU)->getGenericArgs()[0];
|
||||||
|
auto typeName = cast<BoundGenericStructType>(canTypeT)->getDecl()->getName();
|
||||||
|
|
||||||
|
// Get the intrinsic function.
|
||||||
|
FuncDecl *fn = nullptr;
|
||||||
|
|
||||||
|
if (typeName.str() == "Array") {
|
||||||
|
fn = SGF.getASTContext().getArrayBridgeToObjectiveC(nullptr);
|
||||||
|
} else {
|
||||||
|
llvm_unreachable("unsupported array bridge kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute type parameter substitutions.
|
||||||
|
SmallVector<Substitution, 2> subs;
|
||||||
|
|
||||||
|
// Fish out the conformances to _BridgedToObjectiveC and ObjectiveCType from
|
||||||
|
// the the canonical types of T and U's type arguments.
|
||||||
|
auto polyFnType = cast<PolymorphicFunctionType>
|
||||||
|
(fn->getType()->getCanonicalType());
|
||||||
|
auto genericParams = polyFnType->getGenericParameters();
|
||||||
|
|
||||||
|
auto gp1 = genericParams[0].getAsTypeParam();
|
||||||
|
auto archetype = gp1->getArchetype();
|
||||||
|
auto protocolDecls = archetype->getConformsTo();
|
||||||
|
SmallVector<ProtocolConformance *, 1> conformances;
|
||||||
|
|
||||||
|
auto &ctx = SGF.getASTContext();
|
||||||
|
auto dc = protocolDecls[0]->getDeclContext()->getModuleScopeContext();
|
||||||
|
|
||||||
|
auto conformance = ctx.getConformsTo(arrayT->getCanonicalType(),
|
||||||
|
protocolDecls[0])->getPointer();
|
||||||
|
|
||||||
|
conformances.push_back(conformance);
|
||||||
|
|
||||||
|
subs.push_back(Substitution{archetype,
|
||||||
|
arrayT,
|
||||||
|
ctx.AllocateCopy(conformances)});
|
||||||
|
|
||||||
|
if (auto nestedAssocType =
|
||||||
|
archetype->getNestedTypeValue(ctx.getIdentifier("ObjectiveCType"))) {
|
||||||
|
if (auto nestedArchetype =
|
||||||
|
dyn_cast<ArchetypeType>(nestedAssocType.getPointer())) {
|
||||||
|
protocolDecls = nestedArchetype->getConformsTo();
|
||||||
|
SmallVector<ProtocolConformance *, 1> nestedConformances;
|
||||||
|
dc = protocolDecls[0]->getDeclContext()->getModuleScopeContext();
|
||||||
|
auto conformance = ctx.getConformsTo(arrayU->getCanonicalType(),
|
||||||
|
protocolDecls[0])->getPointer();
|
||||||
|
|
||||||
|
nestedConformances.push_back(conformance);
|
||||||
|
subs.push_back(Substitution{nestedArchetype,
|
||||||
|
arrayU,
|
||||||
|
ctx.AllocateCopy(nestedConformances)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto args = {mv};
|
||||||
|
auto emitApply = SGF.emitApplyOfLibraryIntrinsic(loc,
|
||||||
|
fn,
|
||||||
|
subs,
|
||||||
|
args,
|
||||||
|
C);
|
||||||
|
|
||||||
|
return RValue(SGF, E, emitApply);
|
||||||
|
}
|
||||||
|
|
||||||
RValue RValueEmitter::visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E,
|
RValue RValueEmitter::visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E,
|
||||||
SGFContext C) {
|
SGFContext C) {
|
||||||
ManagedValue archetype = SGF.emitRValueAsSingleValue(E->getSubExpr());
|
ManagedValue archetype = SGF.emitRValueAsSingleValue(E->getSubExpr());
|
||||||
|
|||||||
@@ -3384,7 +3384,16 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
|
|||||||
if (!expr) return nullptr;
|
if (!expr) return nullptr;
|
||||||
return coerceToType(expr, toType, locator);
|
return coerceToType(expr, toType, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ConversionRestrictionKind::ArrayBridged: {
|
||||||
|
auto bridgedArrayConversion = new (tc.Context)
|
||||||
|
ArrayBridgedConversionExpr(expr, toType);
|
||||||
|
bridgedArrayConversion->isConditionallyBridged =
|
||||||
|
tc.isConditionallyBridgedType(dc, toType);
|
||||||
|
bridgedArrayConversion->setType(toType);
|
||||||
|
return bridgedArrayConversion;
|
||||||
|
}
|
||||||
|
|
||||||
case ConversionRestrictionKind::ArrayUpcast: {
|
case ConversionRestrictionKind::ArrayUpcast: {
|
||||||
auto arrayConversion = new (tc.Context)
|
auto arrayConversion = new (tc.Context)
|
||||||
ArrayUpcastConversionExpr(expr, toType);
|
ArrayUpcastConversionExpr(expr, toType);
|
||||||
|
|||||||
@@ -57,8 +57,11 @@ void ConstraintSystem::increaseScore(ScoreKind kind) {
|
|||||||
log << "non-default literal";
|
log << "non-default literal";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SK_ArrayConversion:
|
case SK_ArrayUpcastConversion:
|
||||||
log << "array conversion";
|
log << "array upcast conversion";
|
||||||
|
break;
|
||||||
|
case SK_ArrayBridgedConversion:
|
||||||
|
log << "array bridged conversion";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
log << ")\n";
|
log << ")\n";
|
||||||
|
|||||||
@@ -1545,11 +1545,15 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
|
|||||||
conversionsOrFixes.push_back(ConversionRestrictionKind::Superclass);
|
conversionsOrFixes.push_back(ConversionRestrictionKind::Superclass);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array supertype conversions.
|
// Implicit array conversions.
|
||||||
if (kind >= TypeMatchKind::Conversion) {
|
if (kind >= TypeMatchKind::Conversion) {
|
||||||
if (isArrayType(desugar1) && isArrayType(desugar2)) {
|
if (isArrayType(desugar1) && isArrayType(desugar2)) {
|
||||||
conversionsOrFixes.push_back(ConversionRestrictionKind::
|
|
||||||
ArrayUpcast);
|
// Push both the upcast and bridged conversion kinds. We'll construct
|
||||||
|
// a disjunctive constraint out of them, favoring the upcast conversion
|
||||||
|
// should there be a tie.
|
||||||
|
conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast);
|
||||||
|
conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayBridged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2867,7 +2871,7 @@ ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restric
|
|||||||
|
|
||||||
// T < U ===> Array<T> <c Array<U>
|
// T < U ===> Array<T> <c Array<U>
|
||||||
case ConversionRestrictionKind::ArrayUpcast: {
|
case ConversionRestrictionKind::ArrayUpcast: {
|
||||||
increaseScore(SK_ArrayConversion);
|
increaseScore(SK_ArrayUpcastConversion);
|
||||||
|
|
||||||
addContextualScore();
|
addContextualScore();
|
||||||
assert(matchKind >= TypeMatchKind::Conversion);
|
assert(matchKind >= TypeMatchKind::Conversion);
|
||||||
@@ -2892,22 +2896,70 @@ ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restric
|
|||||||
baseType2 = arrayType2->getGenericArgs()[0];
|
baseType2 = arrayType2->getGenericArgs()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow assignments from Array<T> to Array<AnyObject> if T is a bridged
|
|
||||||
// type.
|
|
||||||
if (auto protoTy = baseType2->getAs<ProtocolType>()) {
|
|
||||||
if(protoTy->getDecl()->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
|
|
||||||
if (TC.isTriviallyRepresentableInObjC(DC, baseType1)) {
|
|
||||||
return SolutionKind::Solved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchTypes(baseType1,
|
return matchTypes(baseType1,
|
||||||
baseType2,
|
baseType2,
|
||||||
TypeMatchKind::Subtype,
|
TypeMatchKind::Subtype,
|
||||||
flags,
|
flags,
|
||||||
locator);
|
locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// T < U ===> Array<T> is bridged to Array<U>
|
||||||
|
case ConversionRestrictionKind::ArrayBridged: {
|
||||||
|
addContextualScore();
|
||||||
|
assert(matchKind >= TypeMatchKind::Conversion);
|
||||||
|
|
||||||
|
Type baseType1;
|
||||||
|
Type baseType2;
|
||||||
|
|
||||||
|
auto t1 = type1->getDesugaredType();
|
||||||
|
auto t2 = type2->getDesugaredType();
|
||||||
|
|
||||||
|
if (auto sliceType1 = dyn_cast<ArraySliceType>(t1)) {
|
||||||
|
baseType1 = sliceType1->getBaseType();
|
||||||
|
} else {
|
||||||
|
auto arrayType1 = cast<BoundGenericStructType>(t1);
|
||||||
|
baseType1 = arrayType1->getGenericArgs()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto sliceType2 = dyn_cast<ArraySliceType>(t2)) {
|
||||||
|
baseType2 = sliceType2->getBaseType();
|
||||||
|
} else {
|
||||||
|
auto arrayType2 = cast<BoundGenericStructType>(t2);
|
||||||
|
baseType2 = arrayType2->getGenericArgs()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto nominalType1 = dyn_cast<NominalType>(baseType1.getPointer())) {
|
||||||
|
auto bridgedType1 = TC.getBridgedType(DC, nominalType1);
|
||||||
|
|
||||||
|
// Allow assignments from Array<T> to Array<AnyObject> if T is a bridged
|
||||||
|
// type.
|
||||||
|
if (!bridgedType1.isNull()) {
|
||||||
|
if (auto protoTy = baseType2->getAs<ProtocolType>()) {
|
||||||
|
if(protoTy->getDecl()->isSpecificProtocol(KnownProtocolKind::
|
||||||
|
AnyObject)) {
|
||||||
|
return SolutionKind::Solved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're not converting to AnyObject, check if T.ObjectiveCType is U.
|
||||||
|
// We'll save the further check for conformance with
|
||||||
|
// _ConditionallyBridgedToObjectiveC until runtime.
|
||||||
|
if (bridgedType1.getPointer() == baseType2.getPointer()) {
|
||||||
|
return SolutionKind::Solved;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Check if T's bridged type is a subtype of U.
|
||||||
|
return matchTypes(bridgedType1,
|
||||||
|
baseType2,
|
||||||
|
TypeMatchKind::Subtype,
|
||||||
|
flags,
|
||||||
|
locator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConstraintSystem::SolutionKind::Error;
|
||||||
|
}
|
||||||
|
|
||||||
// T' < U, hasMember(T, conversion, T -> T') ===> T <c U
|
// T' < U, hasMember(T, conversion, T -> T') ===> T <c U
|
||||||
case ConversionRestrictionKind::User:
|
case ConversionRestrictionKind::User:
|
||||||
|
|||||||
@@ -296,6 +296,8 @@ StringRef swift::constraints::getName(ConversionRestrictionKind kind) {
|
|||||||
return "[force-unchecked]";
|
return "[force-unchecked]";
|
||||||
case ConversionRestrictionKind::ArrayUpcast:
|
case ConversionRestrictionKind::ArrayUpcast:
|
||||||
return "[array-upcast]";
|
return "[array-upcast]";
|
||||||
|
case ConversionRestrictionKind::ArrayBridged:
|
||||||
|
return "[array-bridged]";
|
||||||
case ConversionRestrictionKind::User:
|
case ConversionRestrictionKind::User:
|
||||||
return "[user]";
|
return "[user]";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ enum class ConversionRestrictionKind {
|
|||||||
ForceUnchecked,
|
ForceUnchecked,
|
||||||
/// Implicit upcast conversion of array types
|
/// Implicit upcast conversion of array types
|
||||||
ArrayUpcast,
|
ArrayUpcast,
|
||||||
|
/// Implicit bridged conversion between array types
|
||||||
|
ArrayBridged,
|
||||||
/// User-defined conversions.
|
/// User-defined conversions.
|
||||||
User
|
User
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -678,12 +678,14 @@ enum ScoreKind {
|
|||||||
SK_FunctionConversion,
|
SK_FunctionConversion,
|
||||||
/// A literal expression bound to a non-default literal type.
|
/// A literal expression bound to a non-default literal type.
|
||||||
SK_NonDefaultLiteral,
|
SK_NonDefaultLiteral,
|
||||||
/// An implicit conversion between array types.
|
/// An implicit upcast conversion between array types.
|
||||||
SK_ArrayConversion,
|
SK_ArrayUpcastConversion,
|
||||||
|
/// An implicit bridged conversion between array types.
|
||||||
|
SK_ArrayBridgedConversion,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The number of score kinds.
|
/// The number of score kinds.
|
||||||
const unsigned NumScoreKinds = 6;
|
const unsigned NumScoreKinds = 7;
|
||||||
|
|
||||||
/// Describes the fixed score of a solution to the constraint system.
|
/// Describes the fixed score of a solution to the constraint system.
|
||||||
struct Score {
|
struct Score {
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ static void diagModuleOrMetatypeValue(TypeChecker &TC, const Expr *E) {
|
|||||||
case ExprKind::CovariantReturnConversion:
|
case ExprKind::CovariantReturnConversion:
|
||||||
case ExprKind::MetatypeConversion:
|
case ExprKind::MetatypeConversion:
|
||||||
case ExprKind::ArrayUpcastConversion:
|
case ExprKind::ArrayUpcastConversion:
|
||||||
|
case ExprKind::ArrayBridgedConversion:
|
||||||
case ExprKind::Erasure:
|
case ExprKind::Erasure:
|
||||||
case ExprKind::MetatypeErasure:
|
case ExprKind::MetatypeErasure:
|
||||||
case ExprKind::DerivedToBase:
|
case ExprKind::DerivedToBase:
|
||||||
|
|||||||
@@ -120,6 +120,15 @@ Type TypeChecker::getBridgedType(DeclContext *dc, Type type) {
|
|||||||
return Type();
|
return Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TypeChecker::isConditionallyBridgedType(DeclContext *dc, Type type) {
|
||||||
|
auto name = dc->getASTContext().getIdentifier("isBridgedToObjectiveC");
|
||||||
|
auto result = lookupMember(type, name,
|
||||||
|
dc,
|
||||||
|
true);
|
||||||
|
|
||||||
|
return !result.empty();
|
||||||
|
}
|
||||||
|
|
||||||
void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) {
|
void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) {
|
||||||
// Force any delayed members added to the nominal type declaration.
|
// Force any delayed members added to the nominal type declaration.
|
||||||
if (nominalDecl->hasDelayedProtocolDecls() ||
|
if (nominalDecl->hasDelayedProtocolDecls() ||
|
||||||
|
|||||||
@@ -688,6 +688,10 @@ public:
|
|||||||
/// \brief Return the bridged Objective-C type if possbile, otherwise return
|
/// \brief Return the bridged Objective-C type if possbile, otherwise return
|
||||||
/// a null Type.
|
/// a null Type.
|
||||||
Type getBridgedType(DeclContext *dc, Type type);
|
Type getBridgedType(DeclContext *dc, Type type);
|
||||||
|
|
||||||
|
/// \brief Return true if the type conforms to the
|
||||||
|
/// _ConditionallyBridgedToObjectiveC protocol
|
||||||
|
bool isConditionallyBridgedType(DeclContext *dc, Type type);
|
||||||
|
|
||||||
/// \brief Type check the given expression as an array bound, which converts
|
/// \brief Type check the given expression as an array bound, which converts
|
||||||
/// it to a builtin integer value.
|
/// it to a builtin integer value.
|
||||||
|
|||||||
34
test/expr/cast/array_bridge.swift
Normal file
34
test/expr/cast/array_bridge.swift
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// RUN: %swift -parse %s -verify
|
||||||
|
|
||||||
|
class A : ObjCClassType {
|
||||||
|
var x = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : _BridgedToObjectiveC {
|
||||||
|
func bridgeToObjectiveC() -> A {
|
||||||
|
return A()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var a: A[] = []
|
||||||
|
var b: B[] = []
|
||||||
|
|
||||||
|
a = b
|
||||||
|
b = a // expected-error {{cannot convert the expression's type '()' to type 'B[]'}}
|
||||||
|
|
||||||
|
// In this case, bridged conversion should win
|
||||||
|
class E : ObjCClassType {
|
||||||
|
var x = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class F : E, _BridgedToObjectiveC {
|
||||||
|
func bridgeToObjectiveC() -> E {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var e: E[] = []
|
||||||
|
var f: F[] = []
|
||||||
|
|
||||||
|
e = f
|
||||||
|
f = e // expected-error {{cannot convert the expression's type '()' to type 'F[]'}}
|
||||||
Reference in New Issue
Block a user