mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Implement super mesage sends for @objc property and subscript getters/setters.
Fixes <rdar://problem/15933008>. Swift SVN r13100
This commit is contained in:
@@ -102,10 +102,19 @@ class alignas(8) Expr {
|
||||
friend class MemberRefExpr;
|
||||
unsigned : NumExprBits;
|
||||
unsigned IsDirectPropertyAccess : 1;
|
||||
unsigned IsSuper : 1;
|
||||
};
|
||||
enum { NumMemberRefExprBits = NumExprBits + 1 };
|
||||
enum { NumMemberRefExprBits = NumExprBits + 2 };
|
||||
static_assert(NumMemberRefExprBits <= 32, "fits in an unsigned");
|
||||
|
||||
class SubscriptExprBitfields {
|
||||
friend class SubscriptExpr;
|
||||
unsigned : NumExprBits;
|
||||
unsigned IsSuper : 1;
|
||||
};
|
||||
enum { NumSubscriptExprBits = NumExprBits + 1 };
|
||||
static_assert(NumSubscriptExprBits <= 32, "fits in an unsigned");
|
||||
|
||||
class MagicIdentifierLiteralExprBitfields {
|
||||
friend class MagicIdentifierLiteralExpr;
|
||||
unsigned : NumLiteralExprBits;
|
||||
@@ -146,6 +155,7 @@ protected:
|
||||
IntegerLiteralExprBitfields IntegerLiteralExprBits;
|
||||
StringLiteralExprBitfields StringLiteralExprBits;
|
||||
MemberRefExprBitfields MemberRefExprBits;
|
||||
SubscriptExprBitfields SubscriptExprBits;
|
||||
MagicIdentifierLiteralExprBitfields MagicIdentifierLiteralExprBits;
|
||||
AbstractClosureExprBitfields AbstractClosureExprBits;
|
||||
ClosureExprBitfields ClosureExprBits;
|
||||
@@ -783,11 +793,20 @@ public:
|
||||
|
||||
void setBase(Expr *E) { Base = E; }
|
||||
|
||||
/// Return true if this member access is
|
||||
/// Return true if this member access is direct, meaning that it
|
||||
/// does not call the getter or setter.
|
||||
bool isDirectPropertyAccess() const {
|
||||
return MemberRefExprBits.IsDirectPropertyAccess;
|
||||
}
|
||||
|
||||
/// Determine whether this member reference refers to the
|
||||
/// superclass's property.
|
||||
bool isSuper() const { return MemberRefExprBits.IsSuper; }
|
||||
|
||||
/// Set whether this member reference refers to the superclass's
|
||||
/// property.
|
||||
void setIsSuper(bool isSuper) { MemberRefExprBits.IsSuper = isSuper; }
|
||||
|
||||
SourceLoc getLoc() const { return NameLoc; }
|
||||
SourceRange getSourceRange() const {
|
||||
if (Base->isImplicit())
|
||||
@@ -1252,7 +1271,9 @@ public:
|
||||
SubscriptExpr(Expr *base, Expr *index,
|
||||
ConcreteDeclRef decl = ConcreteDeclRef())
|
||||
: Expr(ExprKind::Subscript, /*Implicit=*/false, Type()),
|
||||
TheDecl(decl), Base(base), Index(index) { }
|
||||
TheDecl(decl), Base(base), Index(index) {
|
||||
SubscriptExprBits.IsSuper = false;
|
||||
}
|
||||
|
||||
/// getBase - Retrieve the base of the subscript expression, i.e., the
|
||||
/// value being indexed.
|
||||
@@ -1264,6 +1285,14 @@ public:
|
||||
Expr *getIndex() const { return Index; }
|
||||
void setIndex(Expr *E) { Index = E; }
|
||||
|
||||
/// Determine whether this member reference refers to the
|
||||
/// superclass's property.
|
||||
bool isSuper() const { return SubscriptExprBits.IsSuper; }
|
||||
|
||||
/// Set whether this member reference refers to the superclass's
|
||||
/// property.
|
||||
void setIsSuper(bool isSuper) { SubscriptExprBits.IsSuper = isSuper; }
|
||||
|
||||
/// Determine whether subscript operation has a known underlying
|
||||
/// subscript declaration or not.
|
||||
bool hasDecl() const { return static_cast<bool>(TheDecl); }
|
||||
|
||||
@@ -1090,6 +1090,8 @@ public:
|
||||
|
||||
if (E->isDirectPropertyAccess())
|
||||
OS << " direct_property_access";
|
||||
if (E->isSuper())
|
||||
OS << " super";
|
||||
|
||||
OS << '\n';
|
||||
printRec(E->getBase());
|
||||
@@ -1162,6 +1164,8 @@ public:
|
||||
}
|
||||
void visitSubscriptExpr(SubscriptExpr *E) {
|
||||
printCommon(E, "subscript_expr");
|
||||
if (E->isSuper())
|
||||
OS << " super";
|
||||
OS << '\n';
|
||||
printRec(E->getBase());
|
||||
OS << '\n';
|
||||
|
||||
@@ -197,6 +197,7 @@ MemberRefExpr::MemberRefExpr(Expr *base, SourceLoc dotLoc,
|
||||
Member(member), DotLoc(dotLoc), NameLoc(nameLoc) {
|
||||
|
||||
MemberRefExprBits.IsDirectPropertyAccess = UsesDirectPropertyAccess;
|
||||
MemberRefExprBits.IsSuper = false;
|
||||
}
|
||||
|
||||
ExistentialMemberRefExpr::ExistentialMemberRefExpr(Expr *Base, SourceLoc DotLoc,
|
||||
|
||||
@@ -2410,6 +2410,7 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &gen,
|
||||
SILLocation loc,
|
||||
SILDeclRef constant,
|
||||
RValueSource &selfValue,
|
||||
bool isSuper,
|
||||
CanAnyFunctionType substAccessorType) {
|
||||
ValueDecl *decl = constant.getDecl();
|
||||
|
||||
@@ -2420,6 +2421,10 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &gen,
|
||||
// getters and setters.
|
||||
if (gen.SGM.requiresObjCDispatch(decl)) {
|
||||
auto self = selfValue.forceAndPeekRValue(gen).peekScalarValue();
|
||||
|
||||
if (isSuper)
|
||||
return Callee::forSuperMethod(gen, self, constant, substAccessorType, loc);
|
||||
|
||||
return Callee::forClassMethod(gen, self, constant, substAccessorType, loc);
|
||||
}
|
||||
|
||||
@@ -2431,7 +2436,8 @@ emitSpecializedAccessorFunctionRef(SILGenFunction &gen,
|
||||
SILLocation loc,
|
||||
SILDeclRef constant,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
RValueSource &selfValue)
|
||||
RValueSource &selfValue,
|
||||
bool isSuper)
|
||||
{
|
||||
// If the accessor is a local constant, use it.
|
||||
// FIXME: Can local properties ever be generic?
|
||||
@@ -2457,7 +2463,7 @@ emitSpecializedAccessorFunctionRef(SILGenFunction &gen,
|
||||
// the Self type is generic.
|
||||
// FIXME: Dynamic dispatch for archetype/existential methods.
|
||||
Callee callee = getBaseAccessorFunctionRef(gen, loc, constant, selfValue,
|
||||
substAccessorType);
|
||||
isSuper, substAccessorType);
|
||||
|
||||
// If there are substitutions, specialize the generic accessor.
|
||||
// FIXME: Generic subscript operator could add another layer of
|
||||
@@ -2501,6 +2507,7 @@ ManagedValue SILGenFunction::
|
||||
emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
RValueSource &&selfValue,
|
||||
bool isSuper,
|
||||
RValueSource &&subscripts,
|
||||
SGFContext c) {
|
||||
|
||||
@@ -2509,7 +2516,8 @@ emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl,
|
||||
decl->usesObjCGetterAndSetter());
|
||||
|
||||
Callee getter = emitSpecializedAccessorFunctionRef(*this, loc, get,
|
||||
substitutions, selfValue);
|
||||
substitutions, selfValue,
|
||||
isSuper);
|
||||
CanAnyFunctionType accessType = getter.getSubstFormalType();
|
||||
|
||||
CallEmission emission(*this, std::move(getter));
|
||||
@@ -2533,6 +2541,7 @@ emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl,
|
||||
void SILGenFunction::emitSetAccessor(SILLocation loc, AbstractStorageDecl *decl,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
RValueSource &&selfValue,
|
||||
bool isSuper,
|
||||
RValueSource &&subscripts,
|
||||
RValueSource &&setValue) {
|
||||
SILDeclRef set(decl, SILDeclRef::Kind::Setter,
|
||||
@@ -2540,7 +2549,8 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, AbstractStorageDecl *decl,
|
||||
decl->usesObjCGetterAndSetter());
|
||||
|
||||
Callee setter = emitSpecializedAccessorFunctionRef(*this, loc, set,
|
||||
substitutions, selfValue);
|
||||
substitutions, selfValue,
|
||||
isSuper);
|
||||
CanAnyFunctionType accessType = setter.getSubstFormalType();
|
||||
|
||||
CallEmission emission(*this, std::move(setter));
|
||||
|
||||
@@ -459,7 +459,7 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType,
|
||||
// Global properties have no base or subscript.
|
||||
return emitGetAccessor(loc, var,
|
||||
ArrayRef<Substitution>(), RValueSource(),
|
||||
RValueSource(), C);
|
||||
/*isSuper=*/false, RValueSource(), C);
|
||||
}
|
||||
|
||||
// If the referenced decl isn't a VarDecl, it should be a constant of some
|
||||
@@ -533,6 +533,7 @@ static AbstractionPattern getOrigFormalRValueType(Type formalStorageType) {
|
||||
/// is designed to work with RValue ManagedValue bases that are either +0 or +1.
|
||||
ManagedValue SILGenFunction::
|
||||
emitRValueForPropertyLoad(SILLocation loc, ManagedValue base,
|
||||
bool isSuper,
|
||||
VarDecl *FieldDecl,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
bool isDirectPropertyAccess,
|
||||
@@ -548,7 +549,7 @@ emitRValueForPropertyLoad(SILLocation loc, ManagedValue base,
|
||||
RValueSource baseRV = prepareAccessorBaseArg(loc, base,
|
||||
FieldDecl->getGetter());
|
||||
return emitGetAccessor(loc, FieldDecl, substitutions,
|
||||
std::move(baseRV), RValueSource(), C);
|
||||
std::move(baseRV), isSuper, RValueSource(), C);
|
||||
}
|
||||
|
||||
assert(FieldDecl->hasStorage() &&
|
||||
@@ -1272,7 +1273,8 @@ RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *E, SGFContext C) {
|
||||
// works with +0 bases correctly, we ask for them to come back.
|
||||
ManagedValue base = SGF.emitRValueAsSingleValue(E->getBase(),
|
||||
SGFContext::AllowPlusZero);
|
||||
ManagedValue res = SGF.emitRValueForPropertyLoad(E, base, FieldDecl,
|
||||
ManagedValue res = SGF.emitRValueForPropertyLoad(E, base, E->isSuper(),
|
||||
FieldDecl,
|
||||
E->getMember().getSubstitutions(),
|
||||
E->isDirectPropertyAccess(),
|
||||
E->getType(), C);
|
||||
@@ -1330,7 +1332,8 @@ RValue RValueEmitter::visitSubscriptExpr(SubscriptExpr *E, SGFContext C) {
|
||||
|
||||
ManagedValue MV =
|
||||
SGF.emitGetAccessor(E, decl, E->getDecl().getSubstitutions(),
|
||||
std::move(baseRV), std::move(subscriptRV), C);
|
||||
std::move(baseRV), E->isSuper(),
|
||||
std::move(subscriptRV), C);
|
||||
return RValue(SGF, E, MV);
|
||||
}
|
||||
|
||||
|
||||
@@ -582,7 +582,7 @@ public:
|
||||
|
||||
/// Produce a singular RValue for a load from the specified property.
|
||||
ManagedValue emitRValueForPropertyLoad(SILLocation loc, ManagedValue base,
|
||||
VarDecl *property,
|
||||
bool isSuper, VarDecl *property,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
bool isDirectPropertyAccess,
|
||||
Type propTy, SGFContext C);
|
||||
@@ -601,11 +601,13 @@ public:
|
||||
ManagedValue emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
RValueSource &&optionalSelfValue,
|
||||
bool isSuper,
|
||||
RValueSource &&optionalSubscripts,
|
||||
SGFContext C);
|
||||
void emitSetAccessor(SILLocation loc, AbstractStorageDecl *decl,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
RValueSource &&optionalSelfValue,
|
||||
bool isSuper,
|
||||
RValueSource &&optionalSubscripts,
|
||||
RValueSource &&value);
|
||||
|
||||
|
||||
@@ -341,6 +341,7 @@ namespace {
|
||||
class GetterSetterComponent : public LogicalPathComponent {
|
||||
// The VarDecl or SubscriptDecl being get/set.
|
||||
AbstractStorageDecl *decl;
|
||||
bool IsSuper;
|
||||
std::vector<Substitution> substitutions;
|
||||
Expr *subscriptIndexExpr;
|
||||
mutable RValue origSubscripts;
|
||||
@@ -373,11 +374,13 @@ namespace {
|
||||
|
||||
public:
|
||||
GetterSetterComponent(AbstractStorageDecl *decl,
|
||||
bool isSuper,
|
||||
ArrayRef<Substitution> substitutions,
|
||||
LValueTypeData typeData,
|
||||
Expr *subscriptIndexExpr = nullptr)
|
||||
: LogicalPathComponent(typeData),
|
||||
decl(decl),
|
||||
IsSuper(isSuper),
|
||||
substitutions(substitutions.begin(), substitutions.end()),
|
||||
subscriptIndexExpr(subscriptIndexExpr)
|
||||
{
|
||||
@@ -388,6 +391,7 @@ namespace {
|
||||
SILLocation loc)
|
||||
: LogicalPathComponent(copied.getTypeData()),
|
||||
decl(copied.decl),
|
||||
IsSuper(copied.IsSuper),
|
||||
substitutions(copied.substitutions),
|
||||
subscriptIndexExpr(copied.subscriptIndexExpr),
|
||||
origSubscripts(copied.origSubscripts.copy(gen, loc))
|
||||
@@ -400,7 +404,7 @@ namespace {
|
||||
auto args = prepareAccessorArgs(gen, loc, base, decl->getSetter());
|
||||
|
||||
return gen.emitSetAccessor(loc, decl, substitutions,
|
||||
std::move(args.base),
|
||||
std::move(args.base), IsSuper,
|
||||
std::move(args.subscripts),
|
||||
std::move(rvalue));
|
||||
}
|
||||
@@ -410,7 +414,7 @@ namespace {
|
||||
auto args = prepareAccessorArgs(gen, loc, base, decl->getGetter());
|
||||
|
||||
return gen.emitGetAccessor(loc, decl, substitutions,
|
||||
std::move(args.base),
|
||||
std::move(args.base), IsSuper,
|
||||
std::move(args.subscripts), c);
|
||||
}
|
||||
|
||||
@@ -523,7 +527,8 @@ static LValue emitLValueForNonMemberVarDecl(SILGenFunction &gen,
|
||||
substitutions = gen.buildForwardingSubstitutions(genericParams);
|
||||
}
|
||||
|
||||
lv.add<GetterSetterComponent>(var, substitutions, typeData);
|
||||
lv.add<GetterSetterComponent>(var, /*isSuper=*/false, substitutions,
|
||||
typeData);
|
||||
}
|
||||
}
|
||||
return std::move(lv);
|
||||
@@ -553,8 +558,8 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e) {
|
||||
// Use the property accessors if the variable has accessors and this isn't a
|
||||
// direct access to underlying storage.
|
||||
if (var->hasAccessorFunctions() && !e->isDirectPropertyAccess()) {
|
||||
lv.add<GetterSetterComponent>(var, e->getMember().getSubstitutions(),
|
||||
typeData);
|
||||
lv.add<GetterSetterComponent>(var, e->isSuper(),
|
||||
e->getMember().getSubstitutions(), typeData);
|
||||
return std::move(lv);
|
||||
}
|
||||
|
||||
@@ -597,7 +602,8 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e) {
|
||||
auto typeData = getMemberTypeData(gen, decl->getElementType(), e);
|
||||
|
||||
LValue lv = visitRec(e->getBase());
|
||||
lv.add<GetterSetterComponent>(decl, e->getDecl().getSubstitutions(),
|
||||
lv.add<GetterSetterComponent>(decl, e->isSuper(),
|
||||
e->getDecl().getSubstitutions(),
|
||||
typeData, e->getIndex());
|
||||
return std::move(lv);
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ static SILBasicBlock *emitDispatchAndDestructure(SILGenFunction &gen,
|
||||
|
||||
for (auto &elt : np->getElements()) {
|
||||
ManagedValue MV = ManagedValue::forUnmanaged(v);
|
||||
auto Val = gen.emitRValueForPropertyLoad(loc, MV, elt.getProperty(),
|
||||
auto Val = gen.emitRValueForPropertyLoad(loc, MV, false, elt.getProperty(),
|
||||
// FIXME: No generic substitions.
|
||||
{}, false,
|
||||
elt.getSubPattern()->getType(),
|
||||
|
||||
@@ -401,6 +401,8 @@ namespace {
|
||||
auto &tc = cs.getTypeChecker();
|
||||
auto &context = tc.Context;
|
||||
|
||||
bool isSuper = isa<SuperRefExpr>(base->getSemanticsProvidingExpr());
|
||||
|
||||
Type baseTy = base->getType()->getRValueType();
|
||||
|
||||
// Explicit member accesses are permitted to implicitly look
|
||||
@@ -547,6 +549,7 @@ namespace {
|
||||
= new (context) MemberRefExpr(base, dotLoc, memberRef,
|
||||
memberLoc, Implicit,
|
||||
IsDirectPropertyAccess);
|
||||
result->setIsSuper(isSuper);
|
||||
|
||||
// Skip the synthesized 'self' input type of the opened type.
|
||||
result->setType(simplifyType(openedType));
|
||||
@@ -752,6 +755,9 @@ namespace {
|
||||
auto &tc = cs.getTypeChecker();
|
||||
auto baseTy = base->getType()->getRValueType();
|
||||
|
||||
// Check whether the base is 'super'.
|
||||
bool isSuper = isa<SuperRefExpr>(base->getSemanticsProvidingExpr());
|
||||
|
||||
// Handle accesses that implicitly look through UncheckedOptional<T>.
|
||||
if (auto objTy = cs.lookThroughUncheckedOptionalType(baseTy)) {
|
||||
base = coerceUncheckedOptionalToValue(base, objTy, locator);
|
||||
@@ -844,6 +850,7 @@ namespace {
|
||||
subscript,
|
||||
substitutions));
|
||||
subscriptExpr->setType(resultTy);
|
||||
subscriptExpr->setIsSuper(isSuper);
|
||||
return subscriptExpr;
|
||||
}
|
||||
|
||||
@@ -876,6 +883,7 @@ namespace {
|
||||
auto *subscriptExpr
|
||||
= new (tc.Context) SubscriptExpr(base, index, subscript);
|
||||
subscriptExpr->setType(resultTy);
|
||||
subscriptExpr->setIsSuper(isSuper);
|
||||
return subscriptExpr;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user