mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Remove property behaviors
This commit is contained in:
@@ -1337,390 +1337,6 @@ static void synthesizeLazySetterBody(AbstractFunctionDecl *fn, void *context) {
|
||||
underlyingStorage, ctx);
|
||||
}
|
||||
|
||||
void TypeChecker::completePropertyBehaviorStorage(VarDecl *VD,
|
||||
VarDecl *BehaviorStorage,
|
||||
FuncDecl *DefaultInitStorage,
|
||||
FuncDecl *ParamInitStorage,
|
||||
Type SelfTy,
|
||||
Type StorageTy,
|
||||
NormalProtocolConformance *BehaviorConformance,
|
||||
SubstitutionMap interfaceMap,
|
||||
SubstitutionMap contextMap) {
|
||||
assert(BehaviorStorage);
|
||||
assert((bool)DefaultInitStorage != (bool)ParamInitStorage);
|
||||
|
||||
// Substitute the storage type into the conforming context.
|
||||
auto SubstStorageInterfaceTy = StorageTy.subst(interfaceMap);
|
||||
assert(SubstStorageInterfaceTy && "storage type substitution failed?!");
|
||||
|
||||
auto SubstStorageContextTy = StorageTy.subst(contextMap);
|
||||
assert(SubstStorageContextTy && "storage type substitution failed?!");
|
||||
|
||||
auto DC = VD->getDeclContext();
|
||||
SmallString<64> NameBuf = VD->getName().str();
|
||||
NameBuf += ".storage";
|
||||
auto StorageName = Context.getIdentifier(NameBuf);
|
||||
auto storageSpecifier = BehaviorStorage->isSettable(DC)
|
||||
? VarDecl::Specifier::Var
|
||||
: VarDecl::Specifier::Let;
|
||||
auto *Storage = new (Context) VarDecl(
|
||||
/*IsStatic*/VD->isStatic(), storageSpecifier,
|
||||
/*IsCaptureList*/false, VD->getLoc(), StorageName,
|
||||
DC);
|
||||
Storage->setInterfaceType(SubstStorageInterfaceTy);
|
||||
Storage->setUserAccessible(false);
|
||||
// Mark the vardecl to be final, implicit, and private. In a class, this
|
||||
// prevents it from being dynamically dispatched.
|
||||
if (VD->getDeclContext()->getSelfClassDecl())
|
||||
makeFinal(Context, Storage);
|
||||
Storage->setImplicit();
|
||||
Storage->setAccess(AccessLevel::Private);
|
||||
Storage->setSetterAccess(AccessLevel::Private);
|
||||
|
||||
addMemberToContextIfNeeded(Storage, DC);
|
||||
|
||||
// Initialize the storage immediately, if we can.
|
||||
Expr *InitStorageExpr = nullptr;
|
||||
auto Method = DefaultInitStorage ? DefaultInitStorage : ParamInitStorage;
|
||||
auto SpecializeInitStorage = ConcreteDeclRef(Method, contextMap);
|
||||
|
||||
if (DefaultInitStorage ||
|
||||
(ParamInitStorage && VD->getParentInitializer())) {
|
||||
|
||||
// Build the initializer expression, 'Self.initStorage()', using the
|
||||
// conformance.
|
||||
auto SelfTypeRef = TypeExpr::createImplicit(SelfTy, Context);
|
||||
|
||||
auto InitStorageRef = new (Context) DeclRefExpr(SpecializeInitStorage,
|
||||
DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
auto InitStorageMethodTy = FunctionType::get({}, SubstStorageContextTy);
|
||||
|
||||
FunctionType::Param SelfParam(SelfTypeRef->getType());
|
||||
auto InitStorageRefTy = FunctionType::get({SelfParam}, InitStorageMethodTy);
|
||||
InitStorageRef->setType(InitStorageRefTy);
|
||||
|
||||
auto SelfApply = new (Context) DotSyntaxCallExpr(InitStorageRef,
|
||||
SourceLoc(),
|
||||
SelfTypeRef);
|
||||
SelfApply->setImplicit();
|
||||
SelfApply->setType(InitStorageMethodTy);
|
||||
SelfApply->setThrows(false);
|
||||
|
||||
SmallVector<Expr *, 1> InitStorageArgs;
|
||||
SmallVector<Identifier, 1> InitStorageArgLabels;
|
||||
if (ParamInitStorage) {
|
||||
// Claim the var initializer as the parameter to the `initStorage`
|
||||
// method.
|
||||
auto InitValue = VD->getParentInitializer();
|
||||
auto PBD = VD->getParentPatternBinding();
|
||||
unsigned entryIndex = PBD->getPatternEntryIndexForVarDecl(VD);
|
||||
PBD->setInit(entryIndex, nullptr);
|
||||
PBD->setInitializerChecked(entryIndex);
|
||||
|
||||
// Recontextualize any closure declcontexts nested in the initializer to
|
||||
// realize that they are in the initialization context.
|
||||
InitValue->walk(RecontextualizeClosures(DC));
|
||||
|
||||
// Coerce to the property type.
|
||||
auto PropertyType =
|
||||
Type(contextMap.getGenericSignature()->getGenericParams()[1])
|
||||
.subst(contextMap);
|
||||
InitValue = new (Context) CoerceExpr(InitValue, SourceLoc(),
|
||||
TypeLoc::withoutLoc(PropertyType));
|
||||
// Type-check the expression.
|
||||
typeCheckExpression(InitValue, DC);
|
||||
|
||||
InitStorageArgs.push_back(InitValue);
|
||||
InitStorageArgLabels.push_back(Identifier());
|
||||
}
|
||||
|
||||
auto InitStorageExpr = CallExpr::createImplicit(Context,SelfApply,
|
||||
InitStorageArgs,
|
||||
InitStorageArgLabels);
|
||||
InitStorageExpr->setType(SubstStorageContextTy);
|
||||
InitStorageExpr->setThrows(false);
|
||||
|
||||
} else {
|
||||
// Save the storage property and the initStorage reference for later.
|
||||
// We'll leave it to DI analysis to insert the initializer call at the
|
||||
// right place.
|
||||
auto *Behavior = VD->getMutableBehavior();
|
||||
Behavior->StorageDecl = Storage;
|
||||
Behavior->InitStorageDecl = SpecializeInitStorage;
|
||||
}
|
||||
|
||||
// Create the pattern binding decl for the storage decl. This will get
|
||||
// default initialized using the protocol's initStorage() method.
|
||||
Pattern *PBDPattern = new (Context) NamedPattern(Storage, /*implicit*/true);
|
||||
PBDPattern = TypedPattern::createImplicit(Context, PBDPattern,
|
||||
SubstStorageContextTy);
|
||||
auto *PBD = PatternBindingDecl::createImplicit(
|
||||
Context, VD->getParentPatternBinding()->getStaticSpelling(), PBDPattern,
|
||||
InitStorageExpr, VD->getDeclContext(), /*VarLoc*/ VD->getLoc());
|
||||
PBD->setInitializerChecked(0);
|
||||
addMemberToContextIfNeeded(PBD, VD->getDeclContext(), VD);
|
||||
|
||||
// Add accessors to the storage, since we'll need them to satisfy the
|
||||
// conformance requirements.
|
||||
addTrivialAccessorsToStorage(Storage, Context);
|
||||
|
||||
// FIXME: Hack to eliminate spurious diagnostics.
|
||||
if (BehaviorStorage->isStatic() != Storage->isStatic()) return;
|
||||
|
||||
// Add the witnesses to the conformance.
|
||||
recordKnownWitness(BehaviorConformance, BehaviorStorage, Storage);
|
||||
recordKnownWitness(BehaviorConformance, BehaviorStorage->getGetter(),
|
||||
Storage->getGetter());
|
||||
if (BehaviorStorage->isSettable(DC))
|
||||
recordKnownWitness(BehaviorConformance, BehaviorStorage->getSetter(),
|
||||
Storage->getSetter());
|
||||
}
|
||||
|
||||
void TypeChecker::completePropertyBehaviorParameter(VarDecl *VD,
|
||||
FuncDecl *BehaviorParameter,
|
||||
NormalProtocolConformance *BehaviorConformance,
|
||||
SubstitutionMap interfaceMap) {
|
||||
// Create a method to witness the requirement.
|
||||
auto DC = VD->getDeclContext();
|
||||
SmallString<64> NameBuf = VD->getName().str();
|
||||
NameBuf += ".parameter";
|
||||
auto ParameterBaseName = Context.getIdentifier(NameBuf);
|
||||
|
||||
// Substitute the requirement type into the conforming context.
|
||||
auto ParameterTy = BehaviorParameter->getInterfaceType()
|
||||
->castTo<AnyFunctionType>()
|
||||
->getResult();
|
||||
|
||||
GenericSignature *genericSig = nullptr;
|
||||
GenericEnvironment *genericEnv = nullptr;
|
||||
|
||||
auto SubstInterfaceTy = ParameterTy.subst(interfaceMap);
|
||||
assert(SubstInterfaceTy && "storage type substitution failed?!");
|
||||
|
||||
auto SubstBodyResultTy = SubstInterfaceTy->castTo<AnyFunctionType>()
|
||||
->getResult();
|
||||
|
||||
// Add the Self type back to the interface and context types.
|
||||
if (DC->isTypeContext()) {
|
||||
FunctionType::Param SelfParam(DC->getSelfInterfaceType());
|
||||
|
||||
if (DC->isGenericContext()) {
|
||||
genericSig = DC->getGenericSignatureOfContext();
|
||||
genericEnv = DC->getGenericEnvironmentOfContext();
|
||||
SubstInterfaceTy =
|
||||
GenericFunctionType::get(genericSig, {SelfParam}, SubstInterfaceTy);
|
||||
} else {
|
||||
SubstInterfaceTy =
|
||||
FunctionType::get({SelfParam}, SubstInterfaceTy);
|
||||
}
|
||||
}
|
||||
|
||||
// Borrow the parameters from the requirement declaration.
|
||||
SmallVector<ParamDecl *, 4> Params;
|
||||
SmallVector<Identifier, 4> NameComponents;
|
||||
|
||||
auto *DeclaredParams = BehaviorParameter->getParameters();
|
||||
for (unsigned i : indices(*DeclaredParams)) {
|
||||
auto declaredParam = DeclaredParams->get(i);
|
||||
auto declaredParamTy = declaredParam->getInterfaceType();
|
||||
auto interfaceTy = declaredParamTy.subst(interfaceMap);
|
||||
assert(interfaceTy);
|
||||
auto declaredSpecifier = declaredParam->getSpecifier();
|
||||
|
||||
SmallString<64> ParamNameBuf;
|
||||
{
|
||||
llvm::raw_svector_ostream names(ParamNameBuf);
|
||||
names << "%arg." << i;
|
||||
}
|
||||
auto param = new (Context) ParamDecl(
|
||||
declaredSpecifier, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),
|
||||
Context.getIdentifier(ParamNameBuf), DC);
|
||||
param->setInterfaceType(interfaceTy);
|
||||
param->setImplicit();
|
||||
Params.push_back(param);
|
||||
NameComponents.push_back(Identifier());
|
||||
}
|
||||
auto *ParamList = ParameterList::create(Context, Params);
|
||||
|
||||
auto *Parameter =
|
||||
FuncDecl::create(Context, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None,
|
||||
/*FuncLoc=*/SourceLoc(),
|
||||
DeclName(Context, ParameterBaseName, NameComponents),
|
||||
/*NameLoc=*/SourceLoc(),
|
||||
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
|
||||
/*GenericParams=*/nullptr, ParamList,
|
||||
TypeLoc::withoutLoc(SubstBodyResultTy), DC);
|
||||
|
||||
Parameter->setInterfaceType(SubstInterfaceTy);
|
||||
Parameter->setGenericEnvironment(genericEnv);
|
||||
Parameter->setValidationToChecked();
|
||||
|
||||
// Mark the method to be final, implicit, and private. In a class, this
|
||||
// prevents it from being dynamically dispatched.
|
||||
if (DC->getSelfClassDecl())
|
||||
makeFinal(Context, Parameter);
|
||||
Parameter->setImplicit();
|
||||
Parameter->setAccess(AccessLevel::Private);
|
||||
|
||||
// Recontextualize any closure declcontexts nested in the initializer to
|
||||
// realize that they are in the parameter function.
|
||||
assert(VD->getBehavior()->Param);
|
||||
VD->getBehavior()->Param->walk(RecontextualizeClosures(Parameter));
|
||||
|
||||
// Apply and return the closure in the function context.
|
||||
SmallVector<Expr *, 4> argRefs;
|
||||
SmallVector<Identifier, 4> argNames;
|
||||
for (unsigned i : indices(Params)) {
|
||||
auto param = Params[i];
|
||||
auto expr = new (Context) DeclRefExpr(param, DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
argRefs.push_back(expr);
|
||||
argNames.push_back(DeclaredParams->get(i)->getName());
|
||||
}
|
||||
auto apply = CallExpr::createImplicit(Context, VD->getBehavior()->Param,
|
||||
argRefs, argNames);
|
||||
|
||||
// Return the expression value.
|
||||
auto Ret = new (Context) ReturnStmt(SourceLoc(), apply,
|
||||
/*implicit*/ true);
|
||||
auto Body = BraceStmt::create(Context, SourceLoc(), ASTNode(Ret),
|
||||
SourceLoc(), /*implicit*/ true);
|
||||
Parameter->setBody(Body);
|
||||
|
||||
typeCheckDecl(Parameter);
|
||||
addMemberToContextIfNeeded(Parameter, DC);
|
||||
|
||||
// Add the witnesses to the conformance.
|
||||
recordKnownWitness(BehaviorConformance, BehaviorParameter, Parameter);
|
||||
}
|
||||
|
||||
void TypeChecker::completePropertyBehaviorAccessors(VarDecl *VD,
|
||||
VarDecl *ValueImpl,
|
||||
Type valueTy,
|
||||
SubstitutionMap SelfInterfaceSubs,
|
||||
SubstitutionMap SelfContextSubs) {
|
||||
auto selfGenericParamTy = Type(GenericTypeParamType::get(0, 0, Context));
|
||||
auto selfTy = selfGenericParamTy.subst(SelfContextSubs);
|
||||
auto selfIfaceTy = selfGenericParamTy.subst(SelfInterfaceSubs);
|
||||
|
||||
SmallVector<ASTNode, 3> bodyStmts;
|
||||
|
||||
auto makeSelfExpr = [&](FuncDecl *fromAccessor,
|
||||
FuncDecl *toAccessor) -> Expr * {
|
||||
Expr *selfExpr;
|
||||
if (VD->getDeclContext()->isTypeContext()) {
|
||||
ConcreteDeclRef selfRef = fromAccessor->getImplicitSelfDecl();
|
||||
selfExpr = new (Context) DeclRefExpr(selfRef, DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
|
||||
} else {
|
||||
// self is the empty tuple outside of a type.
|
||||
selfExpr = TupleExpr::createEmpty(Context, SourceLoc(), SourceLoc(),
|
||||
/*implicit*/ true);
|
||||
}
|
||||
|
||||
// If forwarding from a nonmutating to a mutating accessor, we need to put
|
||||
// `self` in a mutable temporary.
|
||||
auto fromMutating = VD->getDeclContext()->isTypeContext()
|
||||
&& fromAccessor->getImplicitSelfDecl()->isSettable(fromAccessor);
|
||||
|
||||
if (!fromMutating
|
||||
&& toAccessor->getImplicitSelfDecl()->isSettable(toAccessor)) {
|
||||
selfExpr->setType(selfTy);
|
||||
auto var = new (Context) VarDecl(/*IsStatic*/false,
|
||||
VarDecl::Specifier::Var,
|
||||
/*IsCaptureList*/false, SourceLoc(),
|
||||
Context.getIdentifier("tempSelf"),
|
||||
fromAccessor);
|
||||
var->setInterfaceType(selfIfaceTy);
|
||||
var->setImplicit();
|
||||
|
||||
auto varPat = new (Context) NamedPattern(var, /*implicit*/ true);
|
||||
auto *pbd = PatternBindingDecl::createImplicit(
|
||||
Context, StaticSpellingKind::None, varPat, selfExpr, fromAccessor);
|
||||
bodyStmts.push_back(var);
|
||||
bodyStmts.push_back(pbd);
|
||||
selfExpr = new (Context) DeclRefExpr(var, DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
}
|
||||
assert((!fromMutating
|
||||
|| toAccessor->getImplicitSelfDecl()->isSettable(toAccessor))
|
||||
&& "can't forward from mutating to nonmutating");
|
||||
if (!toAccessor->isMutating()) {
|
||||
selfExpr->setType(selfTy);
|
||||
} else {
|
||||
// Access the base as inout if the accessor is mutating.
|
||||
auto lvTy = LValueType::get(selfTy);
|
||||
selfExpr->setType(lvTy);
|
||||
selfExpr = new (Context) InOutExpr(SourceLoc(),
|
||||
selfExpr, selfTy, /*implicit*/ true);
|
||||
}
|
||||
return selfExpr;
|
||||
};
|
||||
|
||||
{
|
||||
auto getter = VD->getGetter();
|
||||
assert(getter);
|
||||
|
||||
Expr *selfExpr = makeSelfExpr(getter, ValueImpl->getGetter());
|
||||
|
||||
auto implRef = ConcreteDeclRef(ValueImpl, SelfContextSubs);
|
||||
auto implMemberExpr = new (Context) MemberRefExpr(selfExpr,
|
||||
SourceLoc(),
|
||||
implRef,
|
||||
DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
Expr *returnExpr;
|
||||
if (ValueImpl->isSettable(VD->getDeclContext())) {
|
||||
auto valueLVTy = LValueType::get(valueTy);
|
||||
implMemberExpr->setType(valueLVTy);
|
||||
returnExpr = new (Context) LoadExpr(implMemberExpr,
|
||||
valueTy);
|
||||
returnExpr->setImplicit();
|
||||
} else {
|
||||
implMemberExpr->setType(valueTy);
|
||||
returnExpr = implMemberExpr;
|
||||
}
|
||||
auto returnStmt = new (Context) ReturnStmt(SourceLoc(), returnExpr,
|
||||
/*implicit*/ true);
|
||||
bodyStmts.push_back(returnStmt);
|
||||
auto body = BraceStmt::create(Context, SourceLoc(), bodyStmts, SourceLoc(),
|
||||
/*implicit*/ true);
|
||||
getter->setBody(body);
|
||||
getter->setBodyTypeCheckedIfPresent();
|
||||
}
|
||||
|
||||
bodyStmts.clear();
|
||||
|
||||
if (auto setter = VD->getSetter()) {
|
||||
Expr *selfExpr = makeSelfExpr(setter, ValueImpl->getSetter());
|
||||
auto implRef = ConcreteDeclRef(ValueImpl, SelfContextSubs);
|
||||
auto implMemberExpr = new (Context) MemberRefExpr(selfExpr,
|
||||
SourceLoc(),
|
||||
implRef,
|
||||
DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
auto valueLVTy = LValueType::get(valueTy);
|
||||
implMemberExpr->setType(valueLVTy);
|
||||
|
||||
ConcreteDeclRef newValueRef = getFirstParamDecl(setter);
|
||||
auto newValueExpr = new (Context) DeclRefExpr(newValueRef, DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
newValueExpr->setType(valueTy);
|
||||
|
||||
auto assign = new (Context) AssignExpr(implMemberExpr, SourceLoc(),
|
||||
newValueExpr, /*implicit*/ true);
|
||||
assign->setType(TupleType::getEmpty(Context));
|
||||
|
||||
bodyStmts.push_back(assign);
|
||||
auto body = BraceStmt::create(Context, SourceLoc(), bodyStmts, SourceLoc(),
|
||||
/*implicit*/ true);
|
||||
setter->setBody(body);
|
||||
setter->setBodyTypeCheckedIfPresent();
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::completeLazyVarImplementation(VarDecl *VD) {
|
||||
assert(VD->getAttrs().hasAttribute<LazyAttr>());
|
||||
assert(VD->getReadImpl() == ReadImplKind::Get);
|
||||
@@ -1826,151 +1442,6 @@ void swift::triggerAccessorSynthesis(TypeChecker &TC,
|
||||
});
|
||||
}
|
||||
|
||||
static void maybeAddAccessorsToBehaviorStorage(TypeChecker &TC, VarDecl *var) {
|
||||
// If there's already a getter, we're done.
|
||||
if (var->getGetter())
|
||||
return;
|
||||
|
||||
auto *dc = var->getDeclContext();
|
||||
|
||||
assert(!var->getBehavior()->Conformance.hasValue());
|
||||
|
||||
// The property should be considered computed by the time we're through.
|
||||
SWIFT_DEFER {
|
||||
assert(!var->hasStorage() && "behavior var was not made computed");
|
||||
};
|
||||
|
||||
auto behavior = var->getMutableBehavior();
|
||||
NormalProtocolConformance *conformance = nullptr;
|
||||
VarDecl *valueProp = nullptr;
|
||||
|
||||
bool mightBeMutating = dc->isTypeContext()
|
||||
&& !var->isStatic()
|
||||
&& !dc->getDeclaredInterfaceType()->hasReferenceSemantics();
|
||||
|
||||
auto makeBehaviorAccessors = [&]{
|
||||
AccessorDecl *getter;
|
||||
AccessorDecl *setter = nullptr;
|
||||
if (valueProp && valueProp->getGetter()) {
|
||||
getter = createGetterPrototype(var, TC.Context);
|
||||
// The getter is mutating if the behavior implementation is, unless
|
||||
// we're in a class or non-instance context.
|
||||
if (mightBeMutating && valueProp->isGetterMutating())
|
||||
getter->setSelfAccessKind(SelfAccessKind::Mutating);
|
||||
|
||||
getter->setAccess(var->getFormalAccess());
|
||||
|
||||
// Make a setter if the behavior property has one.
|
||||
if (valueProp->getSetter()) {
|
||||
setter = createSetterPrototype(var, TC.Context, getter);
|
||||
if (mightBeMutating && valueProp->isSetterMutating())
|
||||
setter->setSelfAccessKind(SelfAccessKind::Mutating);
|
||||
// TODO: max of property and implementation setter visibility?
|
||||
setter->setAccess(var->getFormalAccess());
|
||||
}
|
||||
} else {
|
||||
// Even if we couldn't find a value property, still make up a stub
|
||||
// getter and setter, so that subsequent diagnostics make sense for a
|
||||
// computed-ish property.
|
||||
getter = createGetterPrototype(var, TC.Context);
|
||||
getter->setAccess(var->getFormalAccess());
|
||||
setter = createSetterPrototype(var, TC.Context, getter);
|
||||
setter->setSelfAccessKind(SelfAccessKind::NonMutating);
|
||||
setter->setAccess(var->getFormalAccess());
|
||||
}
|
||||
|
||||
SmallVector<AccessorDecl*, 2> accessors;
|
||||
accessors.push_back(getter);
|
||||
auto isMutable = StorageIsMutable_t(setter != nullptr);
|
||||
if (isMutable) accessors.push_back(setter);
|
||||
var->setAccessors(StorageImplInfo::getComputed(isMutable),
|
||||
SourceLoc(), accessors, SourceLoc());
|
||||
|
||||
// Save the conformance and 'value' decl for later type checking.
|
||||
behavior->Conformance = conformance;
|
||||
behavior->ValueDecl = valueProp;
|
||||
};
|
||||
|
||||
// Try to resolve the behavior to a protocol.
|
||||
auto resolution = TypeResolution::forContextual(dc);
|
||||
auto behaviorType = resolution.resolveType(behavior->ProtocolName, None);
|
||||
if (!behaviorType) {
|
||||
return makeBehaviorAccessors();
|
||||
}
|
||||
|
||||
{
|
||||
// The type must refer to a protocol.
|
||||
auto behaviorProtoTy = behaviorType->getAs<ProtocolType>();
|
||||
if (!behaviorProtoTy) {
|
||||
TC.diagnose(behavior->getLoc(),
|
||||
diag::property_behavior_not_protocol);
|
||||
behavior->Conformance = (NormalProtocolConformance*)nullptr;
|
||||
return makeBehaviorAccessors();
|
||||
}
|
||||
auto behaviorProto = behaviorProtoTy->getDecl();
|
||||
|
||||
// Validate the behavior protocol and all its extensions so we can do
|
||||
// name lookup.
|
||||
TC.validateDecl(behaviorProto);
|
||||
for (auto ext : behaviorProto->getExtensions()) {
|
||||
TC.validateExtension(ext);
|
||||
}
|
||||
|
||||
// Look up the behavior protocol's "value" property, or bail if it doesn't
|
||||
// have one. The property's accessors will decide whether the getter
|
||||
// is mutating, and whether there's a setter. We'll type-check to make
|
||||
// sure the property type matches later after validation.
|
||||
auto lookup = TC.lookupMember(dc, behaviorProtoTy, TC.Context.Id_value);
|
||||
for (auto found : lookup) {
|
||||
if (auto foundVar = dyn_cast<VarDecl>(found.getValueDecl())) {
|
||||
if (valueProp) {
|
||||
TC.diagnose(behavior->getLoc(),
|
||||
diag::property_behavior_protocol_reqt_ambiguous,
|
||||
TC.Context.Id_value);
|
||||
TC.diagnose(valueProp->getLoc(), diag::identifier_declared_here,
|
||||
TC.Context.Id_value);
|
||||
TC.diagnose(foundVar->getLoc(), diag::identifier_declared_here,
|
||||
TC.Context.Id_value);
|
||||
break;
|
||||
}
|
||||
|
||||
valueProp = foundVar;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valueProp) {
|
||||
TC.diagnose(behavior->getLoc(),
|
||||
diag::property_behavior_protocol_no_value);
|
||||
return makeBehaviorAccessors();
|
||||
}
|
||||
|
||||
TC.validateDecl(valueProp);
|
||||
var->setIsGetterMutating(mightBeMutating &&
|
||||
valueProp->isGetterMutating());
|
||||
var->setIsSetterMutating(mightBeMutating &&
|
||||
valueProp->isSetterMutating());
|
||||
|
||||
// Set up a conformance to represent the behavior instantiation.
|
||||
// The conformance will be on the containing 'self' type, or '()' if the
|
||||
// property is in a non-type context.
|
||||
Type behaviorSelf;
|
||||
if (dc->isTypeContext()) {
|
||||
behaviorSelf = dc->getSelfInterfaceType();
|
||||
assert(behaviorSelf && "type context doesn't have self type?!");
|
||||
if (var->isStatic())
|
||||
behaviorSelf = MetatypeType::get(behaviorSelf);
|
||||
} else {
|
||||
behaviorSelf = TC.Context.TheEmptyTupleType;
|
||||
}
|
||||
|
||||
conformance = TC.Context.getBehaviorConformance(behaviorSelf,
|
||||
behaviorProto,
|
||||
behavior->getLoc(), var,
|
||||
ProtocolConformanceState::Checking);
|
||||
}
|
||||
return makeBehaviorAccessors();
|
||||
}
|
||||
|
||||
static void maybeAddAccessorsToLazyVariable(VarDecl *var, ASTContext &ctx) {
|
||||
// If there are already accessors, something is invalid; bail out.
|
||||
if (!var->getImplInfo().isSimpleStored())
|
||||
@@ -1997,12 +1468,6 @@ static void maybeAddAccessorsToLazyVariable(VarDecl *var, ASTContext &ctx) {
|
||||
/// - it synthesizes a setter for get+mutableAddress
|
||||
void swift::maybeAddAccessorsToStorage(TypeChecker &TC,
|
||||
AbstractStorageDecl *storage) {
|
||||
// Introduce accessors for a property with behaviors.
|
||||
if (storage->hasBehavior()) {
|
||||
maybeAddAccessorsToBehaviorStorage(TC, cast<VarDecl>(storage));
|
||||
return;
|
||||
}
|
||||
|
||||
// Lazy properties require special handling.
|
||||
if (storage->getAttrs().hasAttribute<LazyAttr>()) {
|
||||
maybeAddAccessorsToLazyVariable(cast<VarDecl>(storage), TC.Context);
|
||||
|
||||
Reference in New Issue
Block a user