Skip to content

Commit 70bcd74

Browse files
committed
Sema: Introduce IsImplicitlyUnwrappedOptionalRequest
1 parent 1c3ac86 commit 70bcd74

File tree

9 files changed

+164
-70
lines changed

9 files changed

+164
-70
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,6 +2425,7 @@ class ValueDecl : public Decl {
24252425
friend class IsObjCRequest;
24262426
friend class IsFinalRequest;
24272427
friend class IsDynamicRequest;
2428+
friend class IsImplicitlyUnwrappedOptionalRequest;
24282429

24292430
protected:
24302431
ValueDecl(DeclKind K,

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,27 @@ class EmittedMembersRequest :
10311031
void cacheResult(DeclRange value) const;
10321032
};
10331033

1034+
class IsImplicitlyUnwrappedOptionalRequest :
1035+
public SimpleRequest<IsImplicitlyUnwrappedOptionalRequest,
1036+
bool(ValueDecl *),
1037+
CacheKind::SeparatelyCached> {
1038+
public:
1039+
using SimpleRequest::SimpleRequest;
1040+
1041+
private:
1042+
friend SimpleRequest;
1043+
1044+
// Evaluation.
1045+
llvm::Expected<bool>
1046+
evaluate(Evaluator &evaluator, ValueDecl *value) const;
1047+
1048+
public:
1049+
// Separate caching.
1050+
bool isCached() const { return true; }
1051+
Optional<bool> getCachedResult() const;
1052+
void cacheResult(bool value) const;
1053+
};
1054+
10341055
// Allow AnyValue to compare two Type values, even though Type doesn't
10351056
// support ==.
10361057
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ SWIFT_TYPEID(RequiresOpaqueModifyCoroutineRequest)
5555
SWIFT_TYPEID(IsAccessorTransparentRequest)
5656
SWIFT_TYPEID(SynthesizeAccessorRequest)
5757
SWIFT_TYPEID(EmittedMembersRequest)
58+
SWIFT_TYPEID(IsImplicitlyUnwrappedOptionalRequest)

include/swift/Parse/Parser.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,6 @@ class Parser {
10191019
ParserStatus parseGetSet(ParseDeclOptions Flags,
10201020
GenericParamList *GenericParams,
10211021
ParameterList *Indices,
1022-
TypeLoc ElementTy,
10231022
ParsedAccessors &accessors,
10241023
AbstractStorageDecl *storage,
10251024
SourceLoc StaticLoc);

lib/AST/Decl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2686,7 +2686,10 @@ bool ValueDecl::canBeAccessedByDynamicLookup() const {
26862686
}
26872687

26882688
bool ValueDecl::isImplicitlyUnwrappedOptional() const {
2689-
return LazySemanticInfo.isIUO;
2689+
ASTContext &ctx = getASTContext();
2690+
return evaluateOrDefault(ctx.evaluator,
2691+
IsImplicitlyUnwrappedOptionalRequest{const_cast<ValueDecl *>(this)},
2692+
false);
26902693
}
26912694

26922695
ArrayRef<ValueDecl *>

lib/AST/TypeCheckRequests.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,3 +807,20 @@ void EmittedMembersRequest::cacheResult(DeclRange result) const {
807807
auto *classDecl = std::get<0>(getStorage());
808808
classDecl->setHasForcedEmittedMembers();
809809
}
810+
811+
//----------------------------------------------------------------------------//
812+
// IsImplicitlyUnwrappedOptionalRequest computation.
813+
//----------------------------------------------------------------------------//
814+
815+
Optional<bool>
816+
IsImplicitlyUnwrappedOptionalRequest::getCachedResult() const {
817+
auto *decl = std::get<0>(getStorage());
818+
if (decl->LazySemanticInfo.isIUOComputed)
819+
return decl->LazySemanticInfo.isIUO;
820+
return None;
821+
}
822+
823+
void IsImplicitlyUnwrappedOptionalRequest::cacheResult(bool value) const {
824+
auto *decl = std::get<0>(getStorage());
825+
decl->setImplicitlyUnwrappedOptional(value);
826+
}

lib/Parse/ParseDecl.cpp

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4278,7 +4278,6 @@ static AccessorDecl *createAccessorFunc(SourceLoc DeclLoc,
42784278
ParameterList *param,
42794279
GenericParamList *GenericParams,
42804280
ParameterList *Indices,
4281-
TypeLoc ElementTy,
42824281
SourceLoc StaticLoc,
42834282
Parser::ParseDeclOptions Flags,
42844283
AccessorKind Kind,
@@ -4361,7 +4360,7 @@ static AccessorDecl *createAccessorFunc(SourceLoc DeclLoc,
43614360
static ParamDecl *createSetterAccessorArgument(SourceLoc nameLoc,
43624361
Identifier name,
43634362
AccessorKind accessorKind,
4364-
Parser &P, TypeLoc elementType) {
4363+
Parser &P) {
43654364
// Add the parameter. If no name was specified, the name defaults to
43664365
// 'value'.
43674366
bool isNameImplicit = name.empty();
@@ -4380,13 +4379,6 @@ static ParamDecl *createSetterAccessorArgument(SourceLoc nameLoc,
43804379
// AST Walker shouldn't go into the type recursively.
43814380
result->setIsTypeLocImplicit(true);
43824381

4383-
if (auto *repr = elementType.getTypeRepr()) {
4384-
if (repr->getKind() ==
4385-
TypeReprKind::ImplicitlyUnwrappedOptional) {
4386-
result->setImplicitlyUnwrappedOptional(true);
4387-
}
4388-
}
4389-
43904382
return result;
43914383
}
43924384

@@ -4395,8 +4387,7 @@ static ParamDecl *createSetterAccessorArgument(SourceLoc nameLoc,
43954387
/// present.
43964388
static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc,
43974389
Parser &P,
4398-
AccessorKind Kind,
4399-
TypeLoc ElementTy) {
4390+
AccessorKind Kind) {
44004391
// 'set' and 'willSet' have a (value) parameter, 'didSet' takes an (oldValue)
44014392
// parameter and 'get' and always takes a () parameter.
44024393
if (Kind != AccessorKind::Set && Kind != AccessorKind::WillSet &&
@@ -4435,7 +4426,7 @@ static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc,
44354426
}
44364427

44374428
if (Name.empty()) NameLoc = SpecifierLoc;
4438-
auto param = createSetterAccessorArgument(NameLoc, Name, Kind, P, ElementTy);
4429+
auto param = createSetterAccessorArgument(NameLoc, Name, Kind, P);
44394430
return ParameterList::create(P.Context, StartLoc, param, EndLoc);
44404431
}
44414432

@@ -4598,7 +4589,7 @@ static bool parseAccessorIntroducer(Parser &P,
45984589
ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
45994590
GenericParamList *GenericParams,
46004591
ParameterList *Indices,
4601-
TypeLoc ElementTy, ParsedAccessors &accessors,
4592+
ParsedAccessors &accessors,
46024593
AbstractStorageDecl *storage,
46034594
SourceLoc StaticLoc) {
46044595
assert(Tok.is(tok::l_brace));
@@ -4637,7 +4628,7 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
46374628
accessors.LBLoc = Tok.getLoc();
46384629
auto getter =
46394630
createAccessorFunc(Tok.getLoc(), /*ValueNamePattern*/ nullptr,
4640-
GenericParams, Indices, ElementTy, StaticLoc, Flags,
4631+
GenericParams, Indices, StaticLoc, Flags,
46414632
AccessorKind::Get, storage, this,
46424633
/*AccessorKeywordLoc*/ SourceLoc());
46434634
accessors.add(getter);
@@ -4681,7 +4672,7 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
46814672
// expression in a multi-statement body.
46824673
auto getter = createAccessorFunc(
46834674
accessors.LBLoc, /*ValueNamePattern*/ nullptr, GenericParams,
4684-
Indices, ElementTy, StaticLoc, Flags, AccessorKind::Get,
4675+
Indices, StaticLoc, Flags, AccessorKind::Get,
46854676
storage, this, /*AccessorKeywordLoc*/ SourceLoc());
46864677
CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
46874678
getter->setBodyParsed(BraceStmt::create(Context, Tok.getLoc(),
@@ -4737,12 +4728,11 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
47374728
if (parsingLimitedSyntax && Tok.is(tok::l_paren)) {
47384729
diagnose(Loc, diag::protocol_setter_name);
47394730
}
4740-
auto *ValueNamePattern =
4741-
parseOptionalAccessorArgument(Loc, *this, Kind, ElementTy);
4731+
auto *ValueNamePattern = parseOptionalAccessorArgument(Loc, *this, Kind);
47424732

47434733
// Set up a function declaration.
47444734
auto accessor = createAccessorFunc(Loc, ValueNamePattern, GenericParams,
4745-
Indices, ElementTy, StaticLoc, Flags,
4735+
Indices, StaticLoc, Flags,
47464736
Kind, storage, this, Loc);
47474737
accessor->getAttrs() = Attributes;
47484738

@@ -4833,13 +4823,6 @@ Parser::parseDeclVarGetSet(Pattern *pattern, ParseDeclOptions Flags,
48334823
Invalid = true;
48344824
}
48354825

4836-
TypeLoc TyLoc;
4837-
if (auto *TP = dyn_cast<TypedPattern>(pattern)) {
4838-
TyLoc = TP->getTypeLoc();
4839-
} else if (!PrimaryVar) {
4840-
TyLoc = TypeLoc::withoutLoc(ErrorType::get(Context));
4841-
}
4842-
48434826
// Create a fake VarDecl and PBD so that we don't have to weaken the
48444827
// formation rule that an AccessorDecl always has a VarDecl.
48454828
VarDecl *storage = PrimaryVar;
@@ -4870,7 +4853,7 @@ Parser::parseDeclVarGetSet(Pattern *pattern, ParseDeclOptions Flags,
48704853
// Parse getter and setter.
48714854
ParsedAccessors accessors;
48724855
auto AccessorStatus = parseGetSet(Flags, /*GenericParams=*/nullptr,
4873-
/*Indices=*/nullptr, TyLoc, accessors,
4856+
/*Indices=*/nullptr, accessors,
48744857
storage, StaticLoc);
48754858
if (AccessorStatus.hasCodeCompletion())
48764859
return makeParserCodeCompletionStatus();
@@ -4881,6 +4864,11 @@ Parser::parseDeclVarGetSet(Pattern *pattern, ParseDeclOptions Flags,
48814864
if (!PrimaryVar)
48824865
return nullptr;
48834866

4867+
TypeLoc TyLoc;
4868+
if (auto *TP = dyn_cast<TypedPattern>(pattern)) {
4869+
TyLoc = TP->getTypeLoc();
4870+
}
4871+
48844872
if (!TyLoc.hasLocation()) {
48854873
if (accessors.Get || accessors.Set || accessors.Address ||
48864874
accessors.MutableAddress) {
@@ -6416,8 +6404,7 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc,
64166404
Status.setIsParseError();
64176405
}
64186406
} else {
6419-
Status |= parseGetSet(Flags, GenericParams,
6420-
Indices.get(), ElementTy.get(),
6407+
Status |= parseGetSet(Flags, GenericParams, Indices.get(),
64216408
accessors, Subscript, StaticLoc);
64226409
}
64236410

lib/Sema/TypeCheckDecl.cpp

Lines changed: 101 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3355,6 +3355,107 @@ void TypeChecker::typeCheckDecl(Decl *D) {
33553355
DeclChecker(*this).visit(D);
33563356
}
33573357

3358+
llvm::Expected<bool>
3359+
IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator,
3360+
ValueDecl *decl) const {
3361+
TypeRepr *TyR = nullptr;
3362+
3363+
switch (decl->getKind()) {
3364+
case DeclKind::Func: {
3365+
TyR = cast<FuncDecl>(decl)->getBodyResultTypeLoc().getTypeRepr();
3366+
break;
3367+
}
3368+
3369+
case DeclKind::Accessor: {
3370+
auto *accessor = cast<AccessorDecl>(decl);
3371+
if (!accessor->isGetter())
3372+
break;
3373+
3374+
auto *storage = accessor->getStorage();
3375+
if (auto *subscript = dyn_cast<SubscriptDecl>(storage))
3376+
TyR = subscript->getElementTypeLoc().getTypeRepr();
3377+
else
3378+
TyR = cast<VarDecl>(storage)->getTypeLoc().getTypeRepr();
3379+
break;
3380+
}
3381+
3382+
case DeclKind::Subscript:
3383+
TyR = cast<SubscriptDecl>(decl)->getElementTypeLoc().getTypeRepr();
3384+
break;
3385+
3386+
case DeclKind::Param: {
3387+
auto *param = cast<ParamDecl>(decl);
3388+
if (param->isSelfParameter())
3389+
return false;
3390+
3391+
// FIXME: This "which accessor parameter am I" dance will come up in
3392+
// other requests too. Factor it out when needed.
3393+
if (auto *accessor = dyn_cast<AccessorDecl>(param->getDeclContext())) {
3394+
auto *storage = accessor->getStorage();
3395+
auto *accessorParams = accessor->getParameters();
3396+
unsigned startIndex = 0;
3397+
3398+
switch (accessor->getAccessorKind()) {
3399+
case AccessorKind::DidSet:
3400+
case AccessorKind::WillSet:
3401+
case AccessorKind::Set:
3402+
if (param == accessorParams->get(0)) {
3403+
// This is the 'newValue' parameter.
3404+
return storage->isImplicitlyUnwrappedOptional();
3405+
}
3406+
3407+
startIndex = 1;
3408+
break;
3409+
3410+
default:
3411+
startIndex = 0;
3412+
break;
3413+
}
3414+
3415+
// If the parameter is not the 'newValue' parameter to a setter, it
3416+
// must be a subscript index parameter.
3417+
auto *subscript = cast<SubscriptDecl>(storage);
3418+
auto *subscriptParams = subscript->getIndices();
3419+
3420+
auto where = llvm::find_if(*accessorParams,
3421+
[param](ParamDecl *other) {
3422+
return other == param;
3423+
});
3424+
assert(where != accessorParams->end());
3425+
unsigned index = where - accessorParams->begin();
3426+
3427+
auto *subscriptParam = subscriptParams->get(index - startIndex);
3428+
3429+
if (param != subscriptParam) {
3430+
// This is the 'subscript(...) { get { ... } set { ... } }' case.
3431+
// This means we cloned the parameter list for each accessor.
3432+
// Delegate to the original parameter.
3433+
return subscriptParam->isImplicitlyUnwrappedOptional();
3434+
}
3435+
3436+
// This is the 'subscript(...) { <<body of getter>> }' case.
3437+
// The subscript and the getter share their ParamDecls.
3438+
// Fall through.
3439+
}
3440+
3441+
// Handle eg, 'inout Int!' or '__owned NSObject!'.
3442+
TyR = param->getTypeLoc().getTypeRepr();
3443+
if (auto *STR = dyn_cast_or_null<SpecifierTypeRepr>(TyR))
3444+
TyR = STR->getBase();
3445+
break;
3446+
}
3447+
3448+
case DeclKind::Var:
3449+
// FIXME: See the comment in validateTypedPattern().
3450+
break;
3451+
3452+
default:
3453+
break;
3454+
}
3455+
3456+
return (TyR && TyR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional);
3457+
}
3458+
33583459
/// Validate the underlying type of the given typealias.
33593460
static void validateTypealiasType(TypeChecker &tc, TypeAliasDecl *typeAlias) {
33603461
TypeResolutionOptions options(
@@ -3582,22 +3683,6 @@ static Type buildAddressorResultType(TypeChecker &TC,
35823683
return pointerType;
35833684
}
35843685

3585-
static TypeLoc getTypeLocForFunctionResult(FuncDecl *FD) {
3586-
auto accessor = dyn_cast<AccessorDecl>(FD);
3587-
if (!accessor) {
3588-
return FD->getBodyResultTypeLoc();
3589-
}
3590-
3591-
assert(accessor->isGetter());
3592-
auto *storage = accessor->getStorage();
3593-
assert(isa<VarDecl>(storage) || isa<SubscriptDecl>(storage));
3594-
3595-
if (auto *subscript = dyn_cast<SubscriptDecl>(storage))
3596-
return subscript->getElementTypeLoc();
3597-
3598-
return cast<VarDecl>(storage)->getTypeLoc();
3599-
}
3600-
36013686
void TypeChecker::validateDecl(ValueDecl *D) {
36023687
// Generic parameters are validated as part of their context.
36033688
if (isa<GenericTypeParamDecl>(D))
@@ -3942,13 +4027,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
39424027

39434028
validateGenericFuncOrSubscriptSignature(FD, FD, FD);
39444029

3945-
if (!isa<AccessorDecl>(FD) || cast<AccessorDecl>(FD)->isGetter()) {
3946-
auto *TyR = getTypeLocForFunctionResult(FD).getTypeRepr();
3947-
if (TyR && TyR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) {
3948-
FD->setImplicitlyUnwrappedOptional(true);
3949-
}
3950-
}
3951-
39524030
// We want the function to be available for name lookup as soon
39534031
// as it has a valid interface type.
39544032
FD->setSignatureIsValidated();
@@ -4040,11 +4118,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
40404118

40414119
validateAttributes(*this, SD);
40424120

4043-
auto *TyR = SD->getElementTypeLoc().getTypeRepr();
4044-
if (TyR && TyR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional)
4045-
SD->setImplicitlyUnwrappedOptional(true);
4046-
4047-
// Perform accessor-related validation.
40484121
if (SD->getOpaqueResultTypeDecl()) {
40494122
if (auto SF = SD->getInnermostDeclContext()->getParentSourceFile()) {
40504123
SF->markDeclWithOpaqueResultTypeAsValidated(SD);

0 commit comments

Comments
 (0)