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

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

View File

@@ -424,13 +424,6 @@ SourceRange TopLevelCodeDecl::getSourceRange() const {
return Body->getSourceRange(); 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 { bool ValueDecl::isDefinition() const {
switch (getKind()) { switch (getKind()) {
@@ -1040,6 +1033,17 @@ GenericTypeParamDecl *ProtocolDecl::getSelf() const {
return getGenericParams()->getParams()[0].getAsTypeParam(); 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 { SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const {
if (!getParentPattern()) if (!getParentPattern())
return getSourceRange(); return getSourceRange();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -412,7 +412,7 @@ namespace {
// No substitutions required; the declaration reference is simple. // No substitutions required; the declaration reference is simple.
containerTy = member->getDeclContext()->getDeclaredTypeOfContext(); containerTy = member->getDeclContext()->getDeclaredTypeOfContext();
memberRef = member; 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 // 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 MetatypeType::get(type, cs.getASTContext());
} }
return cs.TC.getUnopenedTypeOfReference(decl, Type(), return cs.TC.getUnopenedTypeOfReference(decl, Type(), dc,
/*wantInterfaceType=*/true); /*wantInterfaceType=*/true);
} }

View File

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

View File

@@ -334,9 +334,6 @@ Type TypeChecker::getTypeOfRValue(ValueDecl *value, bool wantInterfaceType) {
else else
type = value->getType(); type = value->getType();
if (!value->isReferencedAsLValue())
return type;
// Look at the canonical type just for efficiency. We won't // Look at the canonical type just for efficiency. We won't
// use this as the source of the result. // use this as the source of the result.
CanType canType = type->getCanonicalType(); CanType canType = type->getCanonicalType();
@@ -367,14 +364,14 @@ Type TypeChecker::getTypeOfRValue(ValueDecl *value, bool wantInterfaceType) {
return optTy; return optTy;
}
// Ignore @unowned qualification. // Ignore @unowned qualification.
} else if (isa<UnownedStorageType>(canType)) { if (isa<UnownedStorageType>(canType))
return type->castTo<UnownedStorageType>()->getReferentType(); return type->castTo<UnownedStorageType>()->getReferentType();
// No other transforms necessary. // No other transforms necessary.
} else { return type;
return type;
}
} }
bool TypeChecker::requireOptionalIntrinsics(SourceLoc loc) { bool TypeChecker::requireOptionalIntrinsics(SourceLoc loc) {
@@ -388,9 +385,10 @@ bool TypeChecker::requireOptionalIntrinsics(SourceLoc loc) {
/// doesVarDeclMemberProduceLValue - Return true if a reference to the specified /// doesVarDeclMemberProduceLValue - Return true if a reference to the specified
/// VarDecl should produce an lvalue. If present, baseType indicates the base /// VarDecl should produce an lvalue. If present, baseType indicates the base
/// type of a member reference. /// 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. // Get-only VarDecls always produce rvalues.
if (!VD->isSettable()) if (!VD->isSettable(UseDC))
return false; return false;
// If there is no base, or if the base isn't being used, it is settable. // 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, Type TypeChecker::getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
DeclContext *UseDC,
bool wantInterfaceType) { bool wantInterfaceType) {
if (!value->hasType()) if (!value->hasType())
typeCheckDecl(value, true); 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 // 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). // returned as an rvalue (and the access must be a load).
if (auto *VD = dyn_cast<VarDecl>(value)) if (auto *VD = dyn_cast<VarDecl>(value))
if (doesVarDeclMemberProduceLValue(VD, baseType)) if (doesVarDeclMemberProduceLValue(VD, baseType, UseDC))
return LValueType::get(getTypeOfRValue(value, wantInterfaceType)); return LValueType::get(getTypeOfRValue(value, wantInterfaceType));
@@ -458,9 +457,9 @@ Type TypeChecker::getUnopenedTypeOfReference(ValueDecl *value, Type baseType,
return requestedType; return requestedType;
} }
Expr *TypeChecker::buildCheckedRefExpr(ValueDecl *value, SourceLoc loc, Expr *TypeChecker::buildCheckedRefExpr(ValueDecl *value, DeclContext *UseDC,
bool Implicit) { SourceLoc loc, bool Implicit) {
auto type = getUnopenedTypeOfReference(value); auto type = getUnopenedTypeOfReference(value, Type(), UseDC);
return new (Context) DeclRefExpr(value, loc, Implicit, type); 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, Expr *StmtBuilder::getArgRefExpr(VarDecl *Arg, ArrayRef<unsigned> MemberIndexes,
SourceLoc Loc) const { SourceLoc Loc) const {
Expr *ArgRef = TC.buildCheckedRefExpr(Arg, Loc, /*Implicit=*/true); Expr *ArgRef = TC.buildCheckedRefExpr(Arg, DC, Loc, /*Implicit=*/true);
ArgRef = TC.coerceToRValue(ArgRef); ArgRef = TC.coerceToRValue(ArgRef);
for (unsigned i : MemberIndexes) { for (unsigned i : MemberIndexes) {
bool failed = TC.typeCheckExpression(ArgRef, Arg->getDeclContext(), Type(), 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 = new (Context) TypedPattern(pattern, TypeLoc::withoutLoc(boolTy));
pattern->setType(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(), addToBody(new (Context) PatternBindingDecl(SourceLoc(),
Loc, pattern, init, Loc, pattern, init,
DC)); DC));
@@ -315,8 +315,10 @@ void StmtBuilder::printCollection(VarDecl *Arg, Type KeyTy, Type ValueTy,
// First, print the ", " between elements. // First, print the ", " between elements.
if (firstVar) { if (firstVar) {
// if branch: set first to false // if branch: set first to false
Expr *firstRef = TC.buildCheckedRefExpr(firstVar, Loc, /*Implicit=*/true); Expr *firstRef = TC.buildCheckedRefExpr(firstVar, DC,
Expr *falseRef = TC.buildCheckedRefExpr(falseDecl, Loc, /*Implicit=*/true); Loc, /*Implicit=*/true);
Expr *falseRef = TC.buildCheckedRefExpr(falseDecl, DC,
Loc, /*Implicit=*/true);
Expr *setFirstToFalse Expr *setFirstToFalse
= new (Context) AssignExpr(firstRef, Loc, falseRef, /*Implicit=*/true); = new (Context) AssignExpr(firstRef, Loc, falseRef, /*Implicit=*/true);
Stmt *thenStmt = BraceStmt::create(Context, Loc, 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); Stmt *elseStmt = elseBuilder.createBodyStmt(Loc, Loc);
// if-then-else statement. // 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, loopBuilder.addToBody(new (Context) IfStmt(Loc, firstRef, thenStmt,
Loc, elseStmt)); Loc, elseStmt));
} else { } else {
@@ -662,7 +664,7 @@ void REPLChecker::processREPLTopLevelExpr(Expr *E) {
SF.Decls.push_back(metavarBinding); SF.Decls.push_back(metavarBinding);
// Finally, print the variable's value. // 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); generatePrintOfExpression(vd->getName().str(), E);
} }
@@ -685,7 +687,7 @@ void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) {
// Decl to print it. // Decl to print it.
if (auto *NP = dyn_cast<NamedPattern>(PBD->getPattern()-> if (auto *NP = dyn_cast<NamedPattern>(PBD->getPattern()->
getSemanticsProvidingPattern())) { getSemanticsProvidingPattern())) {
Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), PBD->getStartLoc(), Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), &SF, PBD->getStartLoc(),
/*Implicit=*/true); /*Implicit=*/true);
generatePrintOfExpression(PatternString, E); generatePrintOfExpression(PatternString, E);
return; return;
@@ -729,13 +731,14 @@ void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) {
// Replace the initializer of PBD with a reference to our repl temporary. // 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); E = TC.coerceToMaterializable(E);
PBD->setInit(E, /*checked=*/true); PBD->setInit(E, /*checked=*/true);
SF.Decls.push_back(PBTLCD); SF.Decls.push_back(PBTLCD);
// Finally, print out the result, by referring to the repl temp. // 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); generatePrintOfExpression(PatternString, E);
} }

View File

@@ -648,8 +648,12 @@ public:
/// \param baseType if non-null, return the type of a member reference to /// \param baseType if non-null, return the type of a member reference to
/// this value when the base has the given type /// 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. /// \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); bool wantInterfaceType = false);
/// Return the non-lvalue type-of-reference of the given value. /// Return the non-lvalue type-of-reference of the given value.
@@ -835,7 +839,8 @@ public:
ValueDecl *decl2); ValueDecl *decl2);
/// \brief Build a type-checked reference to the given value. /// \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 /// \brief Build a reference to a declaration, where name lookup returned
/// the given set of declarations. /// the given set of declarations.