Skip to content

Commit

Permalink
AST: Remove Expr's LValueAccessKind
Browse files Browse the repository at this point in the history
  • Loading branch information
slavapestov committed Jul 6, 2018
1 parent 2ec0842 commit 381483b
Show file tree
Hide file tree
Showing 11 changed files with 5 additions and 303 deletions.
35 changes: 1 addition & 34 deletions include/swift/AST/Expr.h
Expand Up @@ -137,11 +137,9 @@ class alignas(8) Expr {
protected:
union { uint64_t OpaqueBits;

SWIFT_INLINE_BITFIELD_BASE(Expr, bitmax(NumExprKindBits,8)+2+1,
SWIFT_INLINE_BITFIELD_BASE(Expr, bitmax(NumExprKindBits,8)+1,
/// The subclass of Expr that this is.
Kind : bitmax(NumExprKindBits,8),
/// How this l-value is used, if it's an l-value.
LValueAccessKind : 2,
/// Whether the Expr represents something directly written in source or
/// it was implicitly generated by the type-checker.
Implicit : 1
Expand Down Expand Up @@ -381,17 +379,12 @@ class alignas(8) Expr {
private:
/// Ty - This is the type of the expression.
Type Ty;

void setLValueAccessKind(AccessKind accessKind) {
Bits.Expr.LValueAccessKind = unsigned(accessKind) + 1;
}

protected:
Expr(ExprKind Kind, bool Implicit, Type Ty = Type()) : Ty(Ty) {
Bits.OpaqueBits = 0;
Bits.Expr.Kind = unsigned(Kind);
Bits.Expr.Implicit = Implicit;
Bits.Expr.LValueAccessKind = 0;
}

public:
Expand Down Expand Up @@ -499,32 +492,6 @@ class alignas(8) Expr {
Bits.Expr.Implicit = Implicit;
}

/// getLValueAccessKind - Determines how this l-value expression is used.
AccessKind getLValueAccessKind() const {
assert(hasLValueAccessKind());
return AccessKind(Bits.Expr.LValueAccessKind - 1);
}
bool hasLValueAccessKind() const {
return Bits.Expr.LValueAccessKind != 0;
}
void clearLValueAccessKind() {
Bits.Expr.LValueAccessKind = 0;
}

/// Set that this l-value expression is used in the given way.
///
/// This information is also correctly propagated to any l-value
/// sub-expressions from which this l-value is derived.
///
/// \param allowOverwrite - true if it's okay if an expression already
/// has an access kind
void propagateLValueAccessKind(AccessKind accessKind,
llvm::function_ref<Type(Expr *)> getType
= [](Expr *E) -> Type {
return E->getType();
},
bool allowOverwrite = false);

/// Retrieves the declaration that is being referenced by this
/// expression, if any.
ConcreteDeclRef getReferencedDecl() const;
Expand Down
5 changes: 0 additions & 5 deletions lib/AST/ASTDumper.cpp
Expand Up @@ -1734,11 +1734,6 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
PrintWithColorRAII(OS, ExprModifierColor) << " implicit";
PrintWithColorRAII(OS, TypeColor) << " type='" << GetTypeOfExpr(E) << '\'';

if (E->hasLValueAccessKind()) {
PrintWithColorRAII(OS, ExprModifierColor)
<< " accessKind=" << getAccessKindString(E->getLValueAccessKind());
}

// If we have a source range and an ASTContext, print the source range.
if (auto Ty = GetTypeOfExpr(E)) {
auto &Ctx = Ty->getASTContext();
Expand Down
20 changes: 0 additions & 20 deletions lib/AST/ASTVerifier.cpp
Expand Up @@ -558,16 +558,6 @@ class Verifier : public ASTWalker {
}
return;
}

// Require an access kind to be set on every l-value expression.
// Note that the empty tuple type is assignable but usually isn't
// an l-value, so we have to be conservative there.
if (E->getType()->hasLValueType() != E->hasLValueAccessKind() &&
!(E->hasLValueAccessKind() && E->getType()->isAssignableType())) {
Out << "l-value expression does not have l-value access kind set\n";
E->print(Out);
abort();
}
}
void verifyChecked(Stmt *S) {}
void verifyChecked(Pattern *P) { }
Expand Down Expand Up @@ -1757,7 +1747,6 @@ class Verifier : public ASTWalker {
Out << "Unexpected types in IdentityExpr\n";
abort();
}
checkSameLValueAccessKind(E, E->getSubExpr(), "IdentityExpr");

verifyCheckedBase(E);
}
Expand Down Expand Up @@ -3136,15 +3125,6 @@ class Verifier : public ASTWalker {
abort();
}

void checkSameLValueAccessKind(Expr *LHS, Expr *RHS, const char *what) {
if (LHS->hasLValueAccessKind() != RHS->hasLValueAccessKind() ||
(LHS->hasLValueAccessKind() &&
LHS->getLValueAccessKind() != RHS->getLValueAccessKind())) {
Out << what << " has a mismatched l-value access kind\n";
abort();
}
}

// Verification utilities.
Type checkMetatypeType(Type type, const char *what) {
auto metatype = type->getAs<AnyMetatypeType>();
Expand Down
173 changes: 0 additions & 173 deletions lib/AST/Expr.cpp
Expand Up @@ -220,179 +220,6 @@ DeclRefExpr *Expr::getMemberOperatorRef() {
return operatorRef;
}

/// Propagate l-value use information to children.
void Expr::propagateLValueAccessKind(AccessKind accessKind,
llvm::function_ref<Type(Expr *)> getType,
bool allowOverwrite) {
/// A visitor class which walks an entire l-value expression.
class PropagateAccessKind
: public ExprVisitor<PropagateAccessKind, void, AccessKind> {
llvm::function_ref<Type(Expr *)> GetType;
#ifndef NDEBUG
bool AllowOverwrite;
#endif
public:
PropagateAccessKind(llvm::function_ref<Type(Expr *)> getType,
bool allowOverwrite) : GetType(getType)
#ifndef NDEBUG
, AllowOverwrite(allowOverwrite)
#endif
{}

void visit(Expr *E, AccessKind kind) {
assert((AllowOverwrite || !E->hasLValueAccessKind()) &&
"l-value access kind has already been set");

assert(GetType(E)->isAssignableType() &&
"setting access kind on non-l-value");
E->setLValueAccessKind(kind);

// Propagate this to sub-expressions.
ASTVisitor::visit(E, kind);
}

#define NON_LVALUE_EXPR(KIND) \
void visit##KIND##Expr(KIND##Expr *, AccessKind accessKind) { \
llvm_unreachable("not an l-value"); \
}
#define LEAF_LVALUE_EXPR(KIND) \
void visit##KIND##Expr(KIND##Expr *E, AccessKind accessKind) {}
#define COMPLETE_PHYSICAL_LVALUE_EXPR(KIND, ACCESSOR) \
void visit##KIND##Expr(KIND##Expr *E, AccessKind accessKind) { \
visit(E->ACCESSOR, accessKind); \
}
#define PARTIAL_PHYSICAL_LVALUE_EXPR(KIND, ACCESSOR) \
void visit##KIND##Expr(KIND##Expr *E, AccessKind accessKind) { \
visit(E->ACCESSOR, getPartialAccessKind(accessKind)); \
}

void visitMemberRefExpr(MemberRefExpr *E, AccessKind accessKind) {
if (!GetType(E->getBase())->hasLValueType()) return;
visit(E->getBase(), getBaseAccessKind(E->getMember(), accessKind));
}
void visitSubscriptExpr(SubscriptExpr *E, AccessKind accessKind) {
if (!GetType(E->getBase())->hasLValueType()) return;
visit(E->getBase(), getBaseAccessKind(E->getDecl(), accessKind));
}
void visitKeyPathApplicationExpr(KeyPathApplicationExpr *E,
AccessKind accessKind) {
if (!GetType(E->getBase())->hasLValueType()) return;
auto kpDecl = GetType(E->getKeyPath())->castTo<BoundGenericType>()
->getDecl();
AccessKind baseAccess;
// A ReferenceWritableKeyPath only reads its base.
if (kpDecl ==
GetType(E)->getASTContext().getReferenceWritableKeyPathDecl())
baseAccess = AccessKind::Read;
else
// Assuming a writable keypath projects a part of the base.
baseAccess = getPartialAccessKind(accessKind);

visit(E->getBase(), baseAccess);
}

static AccessKind getPartialAccessKind(AccessKind accessKind) {
return (accessKind == AccessKind::Read
? accessKind : AccessKind::ReadWrite);
}

static AccessKind getBaseAccessKind(ConcreteDeclRef member,
AccessKind accessKind) {
// We assume writes are partial writes, so the result is always
// either Read or ReadWrite.
auto memberDecl = cast<AbstractStorageDecl>(member.getDecl());

// If we're reading and the getter is mutating, or we're writing
// and the setter is mutating, this is readwrite.
if ((accessKind != AccessKind::Write &&
memberDecl->isGetterMutating()) ||
(accessKind != AccessKind::Read &&
memberDecl->isSetterMutating())) {
return AccessKind::ReadWrite;
}

return AccessKind::Read;
}

void visitTupleExpr(TupleExpr *E, AccessKind accessKind) {
for (auto elt : E->getElements()) {
visit(elt, accessKind);
}
}

void visitOpenExistentialExpr(OpenExistentialExpr *E,
AccessKind accessKind) {
AccessKind oldOpaqueValueAK;
bool opaqueValueHadAK;
if (E->getOpaqueValue()) {
opaqueValueHadAK = E->getOpaqueValue()->hasLValueAccessKind();
oldOpaqueValueAK =
(opaqueValueHadAK ? E->getOpaqueValue()->getLValueAccessKind()
: AccessKind::Read);
}

visit(E->getSubExpr(), accessKind);

if (E->getOpaqueValue()) {
// Propagate the new access kind from the OVE to the original
// existential if we just set or changed it on the OVE.
if (E->getOpaqueValue()->hasLValueAccessKind()) {
auto newOpaqueValueAK = E->getOpaqueValue()->getLValueAccessKind();
if (!opaqueValueHadAK || newOpaqueValueAK != oldOpaqueValueAK)
visit(E->getExistentialValue(), newOpaqueValueAK);
}
}
}

LEAF_LVALUE_EXPR(DeclRef)
LEAF_LVALUE_EXPR(DiscardAssignment)
LEAF_LVALUE_EXPR(DynamicLookup)
LEAF_LVALUE_EXPR(OpaqueValue)
LEAF_LVALUE_EXPR(EditorPlaceholder)
LEAF_LVALUE_EXPR(Error)

COMPLETE_PHYSICAL_LVALUE_EXPR(AnyTry, getSubExpr())
PARTIAL_PHYSICAL_LVALUE_EXPR(BindOptional, getSubExpr())
COMPLETE_PHYSICAL_LVALUE_EXPR(DotSyntaxBaseIgnored, getRHS());
PARTIAL_PHYSICAL_LVALUE_EXPR(ForceValue, getSubExpr())
COMPLETE_PHYSICAL_LVALUE_EXPR(Identity, getSubExpr())
PARTIAL_PHYSICAL_LVALUE_EXPR(TupleElement, getBase())

NON_LVALUE_EXPR(Literal)
NON_LVALUE_EXPR(SuperRef)
NON_LVALUE_EXPR(Type)
NON_LVALUE_EXPR(OtherConstructorDeclRef)
NON_LVALUE_EXPR(Collection)
NON_LVALUE_EXPR(CaptureList)
NON_LVALUE_EXPR(AbstractClosure)
NON_LVALUE_EXPR(InOut)
NON_LVALUE_EXPR(DynamicType)
NON_LVALUE_EXPR(RebindSelfInConstructor)
NON_LVALUE_EXPR(Apply)
NON_LVALUE_EXPR(MakeTemporarilyEscapable)
NON_LVALUE_EXPR(ImplicitConversion)
NON_LVALUE_EXPR(ExplicitCast)
NON_LVALUE_EXPR(OptionalEvaluation)
NON_LVALUE_EXPR(If)
NON_LVALUE_EXPR(Assign)
NON_LVALUE_EXPR(CodeCompletion)
NON_LVALUE_EXPR(ObjCSelector)
NON_LVALUE_EXPR(KeyPath)
NON_LVALUE_EXPR(EnumIsCase)
NON_LVALUE_EXPR(LazyInitializer)

#define UNCHECKED_EXPR(KIND, BASE) \
NON_LVALUE_EXPR(KIND)
#include "swift/AST/ExprNodes.def"

#undef PHYSICAL_LVALUE_EXPR
#undef LEAF_LVALUE_EXPR
#undef NON_LVALUE_EXPR
};

PropagateAccessKind(getType, allowOverwrite).visit(this, accessKind);
}

ConcreteDeclRef Expr::getReferencedDecl() const {
switch (getKind()) {
// No declaration reference.
Expand Down
4 changes: 0 additions & 4 deletions lib/ClangImporter/ImportDecl.cpp
Expand Up @@ -454,7 +454,6 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl,

auto selfRef = new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/true);
selfRef->setType(LValueType::get(selfDecl->getType()));
selfRef->propagateLValueAccessKind(AccessKind::Write);

auto paramRef = new (C) DeclRefExpr(param, DeclNameLoc(),
/*implicit*/ true);
Expand Down Expand Up @@ -1184,7 +1183,6 @@ createDefaultConstructor(ClangImporter::Implementation &Impl,
Expr *lhs = new (context) DeclRefExpr(selfDecl,
DeclNameLoc(), /*Implicit=*/true);
lhs->setType(LValueType::get(selfType));
lhs->propagateLValueAccessKind(AccessKind::Write);

auto emptyTuple = TupleType::getEmpty(context);

Expand Down Expand Up @@ -1326,7 +1324,6 @@ createValueConstructor(ClangImporter::Implementation &Impl,
/*Implicit=*/true,
semantics);
lhs->setType(LValueType::get(var->getType()));
lhs->propagateLValueAccessKind(AccessKind::Write);

// Construct right-hand side.
auto rhs = new (context) DeclRefExpr(valueParameters[paramPos],
Expand Down Expand Up @@ -1474,7 +1471,6 @@ static ConstructorDecl *createRawValueBridgingConstructor(
DeclNameLoc(), /*Implicit=*/true,
AccessSemantics::DirectToStorage);
lhs->setType(LValueType::get(storedType));
lhs->propagateLValueAccessKind(AccessKind::Write);

// Construct right-hand side.
// FIXME: get the parameter from the init, and plug it in here.
Expand Down

0 comments on commit 381483b

Please sign in to comment.