Plumb the DeclContext of the use site down to the "doesVarDeclMemberProduceLValue"

function.  Pretty soon, whether something is an lvalue or not will depend on who is
asking.


Swift SVN r12507
This commit is contained in:
Chris Lattner
2014-01-17 22:14:02 +00:00
parent 17d9bf24bf
commit b4735381d0
13 changed files with 65 additions and 59 deletions

View File

@@ -1353,14 +1353,10 @@ public:
/// Set the interface type for the given value.
void setInterfaceType(Type type);
/// isReferencedAsLValue - Returns 'true' if references to this
/// declaration are l-values.
bool isReferencedAsLValue() const;
/// isSettable - Determine whether references to this decl may appear
/// on the left-hand side of an assignment or as the operand of a
/// `&` or @assignment operator.
bool isSettable() const;
bool isSettable(DeclContext *UseDC) const;
/// isInstanceMember - Determine whether this value is an instance member
/// of an enum or protocol.
@@ -2376,14 +2372,10 @@ public:
Type getSetterType() const;
Type getSetterInterfaceType() const;
/// \brief Returns whether the var is settable, either because it is a
/// stored var or because it has a custom setter.
bool isSettable() const {
// 'let' properties are always immutable.
if (isLet()) return false;
return !GetSet || GetSet->Set;
}
/// \brief Returns whether the var is settable in the specified context: this
/// is either because it is a stored var, because it has a custom setter, or
/// is a let member in an initializer.
bool isSettable(DeclContext *UseDC) const;
VarDecl *getOverriddenDecl() const {
return OverriddenDecl;
@@ -3454,9 +3446,9 @@ inline void GenericParam::setDeclContext(DeclContext *DC) {
TypeParam->setDeclContext(DC);
}
inline bool ValueDecl::isSettable() const {
inline bool ValueDecl::isSettable(DeclContext *UseDC) const {
if (auto vd = dyn_cast<VarDecl>(this)) {
return vd->isSettable();
return vd->isSettable(UseDC);
} else if (auto sd = dyn_cast<SubscriptDecl>(this)) {
return sd->isSettable();
} else

View File

@@ -424,13 +424,6 @@ SourceRange TopLevelCodeDecl::getSourceRange() const {
return Body->getSourceRange();
}
/// isReferencedAsLValue - Returns 'true' if references to this
/// declaration are l-values.
bool ValueDecl::isReferencedAsLValue() const {
if (auto *VD = dyn_cast<VarDecl>(this))
return VD->isSettable();
return false;
}
bool ValueDecl::isDefinition() const {
switch (getKind()) {
@@ -1040,6 +1033,17 @@ GenericTypeParamDecl *ProtocolDecl::getSelf() const {
return getGenericParams()->getParams()[0].getAsTypeParam();
}
/// \brief Returns whether the var is settable in the specified context: this
/// is either because it is a stored var, because it has a custom setter, or
/// is a let member in an initializer.
bool VarDecl::isSettable(DeclContext *UseDC) const {
// 'let' properties are always immutable.
if (isLet()) return false;
return !GetSet || GetSet->Set;
}
SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const {
if (!getParentPattern())
return getSourceRange();

View File

@@ -1376,7 +1376,7 @@ namespace {
// FIXME: Emit attributes for (nonatomic, strong) if the property has a
// setter, or (nonatomic, readonly) if the property has only a getter.
// Are these attributes always appropriate?
outs << (prop->isSettable()
outs << (prop->isSettable(prop->getDeclContext())
? ",&,N" // strong, nonatomic
: ",R,N"); // readonly, nonatomic

View File

@@ -187,7 +187,7 @@ public:
llvm::Value *getterArgs[] = {classMetadata, sel, imp, types};
IGF.Builder.CreateCall(class_replaceMethod, getterArgs);
if (prop->isSettable()) {
if (prop->isSettable(prop->getDeclContext())) {
emitObjCSetterDescriptorParts(IGF.IGM, prop,
name, types, imp);
sel = IGF.Builder.CreateCall(IGF.IGM.getObjCSelRegisterNameFn(),

View File

@@ -799,7 +799,8 @@ static llvm::Constant *getObjCSetterPointer(IRGenModule &IGM,
if (isa<ProtocolDecl>(property->getDeclContext()))
return llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
assert(property->isSettable() && "property is not settable?!");
assert(property->isSettable(property->getDeclContext()) &&
"property is not settable?!");
ResilienceExpansion expansion = ResilienceExpansion::Minimal;
SILDeclRef setter = SILDeclRef(property, SILDeclRef::Kind::Setter,
@@ -1043,7 +1044,8 @@ void irgen::emitObjCSetterDescriptorParts(IRGenModule &IGM,
llvm::Constant *&selectorRef,
llvm::Constant *&atEncoding,
llvm::Constant *&impl) {
assert(property->isSettable() && "not a settable property?!");
assert(property->isSettable(property->getDeclContext()) &&
"not a settable property?!");
bool isClassProperty = hasObjCClassRepresentation(IGM, property->getType());
@@ -1133,7 +1135,7 @@ irgen::emitObjCPropertyMethodDescriptors(IRGenModule &IGM,
getterFields);
llvm::Constant *setter = nullptr;
if (property->isSettable()) {
if (property->isSettable(property->getDeclContext())) {
emitObjCSetterDescriptorParts(IGM, property,
selectorRef, atEncoding, impl);

View File

@@ -118,7 +118,8 @@ static CanType getKnownType(Optional<CanType> &cacheSlot,
CaptureKind Lowering::getDeclCaptureKind(ValueDecl *capture) {
if (VarDecl *var = dyn_cast<VarDecl>(capture)) {
if (var->isComputed())
return var->isSettable()? CaptureKind::GetterSetter : CaptureKind::Getter;
return var->getSetter()
? CaptureKind::GetterSetter : CaptureKind::Getter;
if (var->isLet())
return CaptureKind::Constant;

View File

@@ -657,7 +657,7 @@ void SILGenModule::emitObjCPropertyMethodThunks(VarDecl *prop) {
postEmitFunction(getter, f);
}
if (!prop->isSettable())
if (!prop->isSettable(prop->getDeclContext()))
return;
// FIXME: Add proper location.

View File

@@ -459,7 +459,7 @@ ManagedValue SILGenFunction::emitReferenceToDecl(SILLocation loc,
}
if (var->isComputed()) {
assert(!var->isSettable() &&
assert(!var->getSetter() &&
"computed lvalue decls are handled by lvalue machinery");
// Global properties have no base or subscript.
return emitGetAccessor(loc, var,

View File

@@ -412,7 +412,7 @@ namespace {
// No substitutions required; the declaration reference is simple.
containerTy = member->getDeclContext()->getDeclaredTypeOfContext();
memberRef = member;
refTy = tc.getUnopenedTypeOfReference(member);
refTy = tc.getUnopenedTypeOfReference(member, Type(), dc);
}
// If we're referring to the member of a module, it's just a simple
@@ -1207,7 +1207,7 @@ namespace {
return MetatypeType::get(type, cs.getASTContext());
}
return cs.TC.getUnopenedTypeOfReference(decl, Type(),
return cs.TC.getUnopenedTypeOfReference(decl, Type(), dc,
/*wantInterfaceType=*/true);
}

View File

@@ -647,7 +647,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
}
// Determine the type of the value, opening up that type if necessary.
Type valueType = TC.getUnopenedTypeOfReference(value, Type(),
Type valueType = TC.getUnopenedTypeOfReference(value, Type(), DC,
/*wantInterfaceType=*/true);
// Adjust the type of the reference.
@@ -843,7 +843,7 @@ ConstraintSystem::getTypeOfMemberReference(Type baseTy, ValueDecl *value,
openedType = openType(genericFn, dc, /*skipProtocolSelfConstraint=*/true,
opener);
} else {
openedType = TC.getUnopenedTypeOfReference(value, baseTy,
openedType = TC.getUnopenedTypeOfReference(value, baseTy, DC,
/*wantInterfaceType=*/true);
Type selfTy;

View File

@@ -334,9 +334,6 @@ Type TypeChecker::getTypeOfRValue(ValueDecl *value, bool wantInterfaceType) {
else
type = value->getType();
if (!value->isReferencedAsLValue())
return type;
// Look at the canonical type just for efficiency. We won't
// use this as the source of the result.
CanType canType = type->getCanonicalType();
@@ -367,14 +364,14 @@ Type TypeChecker::getTypeOfRValue(ValueDecl *value, bool wantInterfaceType) {
return optTy;
}
// Ignore @unowned qualification.
} else if (isa<UnownedStorageType>(canType)) {
if (isa<UnownedStorageType>(canType))
return type->castTo<UnownedStorageType>()->getReferentType();
// No other transforms necessary.
} else {
return type;
}
}
bool TypeChecker::requireOptionalIntrinsics(SourceLoc loc) {
@@ -388,9 +385,10 @@ bool TypeChecker::requireOptionalIntrinsics(SourceLoc loc) {
/// doesVarDeclMemberProduceLValue - Return true if a reference to the specified
/// VarDecl should produce an lvalue. If present, baseType indicates the base
/// type of a member reference.
static bool doesVarDeclMemberProduceLValue(VarDecl *VD, Type baseType) {
static bool doesVarDeclMemberProduceLValue(VarDecl *VD, Type baseType,
DeclContext *UseDC) {
// Get-only VarDecls always produce rvalues.
if (!VD->isSettable())
if (!VD->isSettable(UseDC))
return false;
// If there is no base, or if the base isn't being used, it is settable.
@@ -426,6 +424,7 @@ static bool doesSubscriptDeclProduceLValue(SubscriptDecl *SD, Type baseType) {
}
Type TypeChecker::getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
DeclContext *UseDC,
bool wantInterfaceType) {
if (!value->hasType())
typeCheckDecl(value, true);
@@ -437,7 +436,7 @@ Type TypeChecker::getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
// has lvalue type. If we are accessing a var member on an rvalue, it is
// returned as an rvalue (and the access must be a load).
if (auto *VD = dyn_cast<VarDecl>(value))
if (doesVarDeclMemberProduceLValue(VD, baseType))
if (doesVarDeclMemberProduceLValue(VD, baseType, UseDC))
return LValueType::get(getTypeOfRValue(value, wantInterfaceType));
@@ -458,9 +457,9 @@ Type TypeChecker::getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
return requestedType;
}
Expr *TypeChecker::buildCheckedRefExpr(ValueDecl *value, SourceLoc loc,
bool Implicit) {
auto type = getUnopenedTypeOfReference(value);
Expr *TypeChecker::buildCheckedRefExpr(ValueDecl *value, DeclContext *UseDC,
SourceLoc loc, bool Implicit) {
auto type = getUnopenedTypeOfReference(value, Type(), UseDC);
return new (Context) DeclRefExpr(value, loc, Implicit, type);
}

View File

@@ -144,7 +144,7 @@ void StmtBuilder::printStruct(VarDecl *Arg, Type SugarT, StructDecl *SD,
Expr *StmtBuilder::getArgRefExpr(VarDecl *Arg, ArrayRef<unsigned> MemberIndexes,
SourceLoc Loc) const {
Expr *ArgRef = TC.buildCheckedRefExpr(Arg, Loc, /*Implicit=*/true);
Expr *ArgRef = TC.buildCheckedRefExpr(Arg, DC, Loc, /*Implicit=*/true);
ArgRef = TC.coerceToRValue(ArgRef);
for (unsigned i : MemberIndexes) {
bool failed = TC.typeCheckExpression(ArgRef, Arg->getDeclContext(), Type(),
@@ -254,7 +254,7 @@ void StmtBuilder::printCollection(VarDecl *Arg, Type KeyTy, Type ValueTy,
pattern = new (Context) TypedPattern(pattern, TypeLoc::withoutLoc(boolTy));
pattern->setType(boolTy);
Expr *init = TC.buildCheckedRefExpr(trueDecl, Loc, /*Implicit=*/true);
Expr *init = TC.buildCheckedRefExpr(trueDecl, DC, Loc, /*Implicit=*/true);
addToBody(new (Context) PatternBindingDecl(SourceLoc(),
Loc, pattern, init,
DC));
@@ -315,8 +315,10 @@ void StmtBuilder::printCollection(VarDecl *Arg, Type KeyTy, Type ValueTy,
// First, print the ", " between elements.
if (firstVar) {
// if branch: set first to false
Expr *firstRef = TC.buildCheckedRefExpr(firstVar, Loc, /*Implicit=*/true);
Expr *falseRef = TC.buildCheckedRefExpr(falseDecl, Loc, /*Implicit=*/true);
Expr *firstRef = TC.buildCheckedRefExpr(firstVar, DC,
Loc, /*Implicit=*/true);
Expr *falseRef = TC.buildCheckedRefExpr(falseDecl, DC,
Loc, /*Implicit=*/true);
Expr *setFirstToFalse
= new (Context) AssignExpr(firstRef, Loc, falseRef, /*Implicit=*/true);
Stmt *thenStmt = BraceStmt::create(Context, Loc,
@@ -329,7 +331,7 @@ void StmtBuilder::printCollection(VarDecl *Arg, Type KeyTy, Type ValueTy,
Stmt *elseStmt = elseBuilder.createBodyStmt(Loc, Loc);
// if-then-else statement.
firstRef = TC.buildCheckedRefExpr(firstVar, Loc, /*Implicit=*/true);
firstRef = TC.buildCheckedRefExpr(firstVar, DC, Loc, /*Implicit=*/true);
loopBuilder.addToBody(new (Context) IfStmt(Loc, firstRef, thenStmt,
Loc, elseStmt));
} else {
@@ -662,7 +664,7 @@ void REPLChecker::processREPLTopLevelExpr(Expr *E) {
SF.Decls.push_back(metavarBinding);
// Finally, print the variable's value.
E = TC.buildCheckedRefExpr(vd, E->getStartLoc(), /*Implicit=*/true);
E = TC.buildCheckedRefExpr(vd, &SF, E->getStartLoc(), /*Implicit=*/true);
generatePrintOfExpression(vd->getName().str(), E);
}
@@ -685,7 +687,7 @@ void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) {
// Decl to print it.
if (auto *NP = dyn_cast<NamedPattern>(PBD->getPattern()->
getSemanticsProvidingPattern())) {
Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), PBD->getStartLoc(),
Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), &SF, PBD->getStartLoc(),
/*Implicit=*/true);
generatePrintOfExpression(PatternString, E);
return;
@@ -729,13 +731,14 @@ void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) {
// Replace the initializer of PBD with a reference to our repl temporary.
Expr *E = TC.buildCheckedRefExpr(vd, vd->getStartLoc(), /*Implicit=*/true);
Expr *E = TC.buildCheckedRefExpr(vd, &SF,
vd->getStartLoc(), /*Implicit=*/true);
E = TC.coerceToMaterializable(E);
PBD->setInit(E, /*checked=*/true);
SF.Decls.push_back(PBTLCD);
// Finally, print out the result, by referring to the repl temp.
E = TC.buildCheckedRefExpr(vd, vd->getStartLoc(), /*Implicit=*/true);
E = TC.buildCheckedRefExpr(vd, &SF, vd->getStartLoc(), /*Implicit=*/true);
generatePrintOfExpression(PatternString, E);
}

View File

@@ -648,8 +648,12 @@ public:
/// \param baseType if non-null, return the type of a member reference to
/// this value when the base has the given type
///
/// \param UseDC The context of the access. Some variables have different
/// types depending on where they are used.
///
/// \param wantInterfaceType Whether we want the interface type, if available.
Type getUnopenedTypeOfReference(ValueDecl *value, Type baseType = Type(),
Type getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
DeclContext *UseDC,
bool wantInterfaceType = false);
/// Return the non-lvalue type-of-reference of the given value.
@@ -835,7 +839,8 @@ public:
ValueDecl *decl2);
/// \brief Build a type-checked reference to the given value.
Expr *buildCheckedRefExpr(ValueDecl *D, SourceLoc nameLoc, bool Implicit);
Expr *buildCheckedRefExpr(ValueDecl *D, DeclContext *UseDC,
SourceLoc nameLoc, bool Implicit);
/// \brief Build a reference to a declaration, where name lookup returned
/// the given set of declarations.