Skip to content

Commit 9b514db

Browse files
authored
Merge pull request #26806 from CodaFi/hello-operator-please-give-me-decl-nine
Requestify Operator Decl Attachment
2 parents 870daf3 + 441eba1 commit 9b514db

File tree

8 files changed

+85
-52
lines changed

8 files changed

+85
-52
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ SWIFT_TYPEID(CtorInitializerKind)
2727
SWIFT_TYPEID(ResilienceExpansion)
2828
SWIFT_TYPEID_NAMED(Optional<PropertyWrapperMutability>, PropertyWrapperMutability)
2929
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
30+
SWIFT_TYPEID_NAMED(OperatorDecl *, OperatorDecl)
3031
SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl)
3132
SWIFT_TYPEID(AncestryFlags)
3233
SWIFT_TYPEID_NAMED(GenericSignature *, GenericSignature)

include/swift/AST/Decl.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5926,7 +5926,6 @@ class FuncDecl : public AbstractFunctionDecl {
59265926

59275927
TypeLoc FnRetType;
59285928

5929-
OperatorDecl *Operator = nullptr;
59305929
OpaqueTypeDecl *OpaqueReturn = nullptr;
59315930

59325931
protected:
@@ -6073,13 +6072,7 @@ class FuncDecl : public AbstractFunctionDecl {
60736072
return cast_or_null<FuncDecl>(AbstractFunctionDecl::getOverriddenDecl());
60746073
}
60756074

6076-
OperatorDecl *getOperatorDecl() const {
6077-
return Operator;
6078-
}
6079-
void setOperatorDecl(OperatorDecl *o) {
6080-
assert(isOperator() && "can't set an OperatorDecl for a non-operator");
6081-
Operator = o;
6082-
}
6075+
OperatorDecl *getOperatorDecl() const;
60836076

60846077
OpaqueTypeDecl *getOpaqueResultTypeDecl() const {
60856078
return OpaqueReturn;

include/swift/AST/TypeCheckRequests.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,6 @@ class ClassAncestryFlagsRequest :
10671067
// Evaluation.
10681068
llvm::Expected<AncestryFlags>
10691069
evaluate(Evaluator &evaluator, ClassDecl *value) const;
1070-
10711070
public:
10721071
// Caching.
10731072
bool isCached() const { return true; }
@@ -1116,7 +1115,25 @@ class ExtendedTypeRequest
11161115

11171116
// Evaluation.
11181117
llvm::Expected<Type> evaluate(Evaluator &eval, ExtensionDecl *) const;
1118+
public:
1119+
// Caching.
1120+
bool isCached() const { return true; }
1121+
};
11191122

1123+
class FunctionOperatorRequest :
1124+
public SimpleRequest<FunctionOperatorRequest,
1125+
OperatorDecl *(FuncDecl *),
1126+
CacheKind::Cached> {
1127+
public:
1128+
using SimpleRequest::SimpleRequest;
1129+
1130+
private:
1131+
friend SimpleRequest;
1132+
1133+
// Evaluation.
1134+
llvm::Expected<OperatorDecl *>
1135+
evaluate(Evaluator &evaluator, FuncDecl *value) const;
1136+
11201137
public:
11211138
// Caching.
11221139
bool isCached() const { return true; }

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@ SWIFT_TYPEID(IsImplicitlyUnwrappedOptionalRequest)
5959
SWIFT_TYPEID(ClassAncestryFlagsRequest)
6060
SWIFT_TYPEID(AbstractGenericSignatureRequest)
6161
SWIFT_TYPEID(ExtendedTypeRequest)
62+
SWIFT_TYPEID(FunctionOperatorRequest)

lib/AST/Decl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6887,6 +6887,18 @@ FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc,
68876887
FD->getBodyResultTypeLoc() = FnRetType;
68886888
return FD;
68896889
}
6890+
6891+
OperatorDecl *FuncDecl::getOperatorDecl() const {
6892+
// Fast-path: Most functions are not operators.
6893+
if (!isOperator()) {
6894+
return nullptr;
6895+
}
6896+
return evaluateOrDefault(getASTContext().evaluator,
6897+
FunctionOperatorRequest{
6898+
const_cast<FuncDecl *>(this)
6899+
},
6900+
nullptr);
6901+
}
68906902

68916903
AccessorDecl *AccessorDecl::createImpl(ASTContext &ctx,
68926904
SourceLoc declLoc,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3430,19 +3430,19 @@ static void validateTypealiasType(TypeChecker &tc, TypeAliasDecl *typeAlias) {
34303430
}
34313431

34323432

3433-
/// Bind the given function declaration, which declares an operator, to
3434-
/// the corresponding operator declaration.
3435-
void bindFuncDeclToOperator(TypeChecker &TC, FuncDecl *FD) {
3436-
OperatorDecl *op = nullptr;
3433+
/// Bind the given function declaration, which declares an operator, to the corresponding operator declaration.
3434+
llvm::Expected<OperatorDecl *>
3435+
FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
3436+
auto &C = FD->getASTContext();
3437+
auto &diags = C.Diags;
34373438
auto operatorName = FD->getFullName().getBaseIdentifier();
34383439

34393440
// Check for static/final/class when we're in a type.
34403441
auto dc = FD->getDeclContext();
34413442
if (dc->isTypeContext()) {
34423443
if (!FD->isStatic()) {
3443-
TC.diagnose(FD->getLoc(), diag::nonstatic_operator_in_type,
3444-
operatorName,
3445-
dc->getDeclaredInterfaceType())
3444+
FD->diagnose(diag::nonstatic_operator_in_type,
3445+
operatorName, dc->getDeclaredInterfaceType())
34463446
.fixItInsert(FD->getAttributeInsertionLoc(/*forModifier=*/true),
34473447
"static ");
34483448

@@ -3451,17 +3451,18 @@ void bindFuncDeclToOperator(TypeChecker &TC, FuncDecl *FD) {
34513451
// For a class, we also need the function or class to be 'final'.
34523452
if (!classDecl->isFinal() && !FD->isFinal() &&
34533453
FD->getStaticSpelling() != StaticSpellingKind::KeywordStatic) {
3454-
TC.diagnose(FD->getLoc(), diag::nonfinal_operator_in_class,
3455-
operatorName, dc->getDeclaredInterfaceType())
3454+
FD->diagnose(diag::nonfinal_operator_in_class,
3455+
operatorName, dc->getDeclaredInterfaceType())
34563456
.fixItInsert(FD->getAttributeInsertionLoc(/*forModifier=*/true),
34573457
"final ");
3458-
FD->getAttrs().add(new (TC.Context) FinalAttr(/*IsImplicit=*/true));
3458+
FD->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
34593459
}
34603460
}
34613461
} else if (!dc->isModuleScopeContext()) {
3462-
TC.diagnose(FD, diag::operator_in_local_scope);
3462+
FD->diagnose(diag::operator_in_local_scope);
34633463
}
34643464

3465+
OperatorDecl *op = nullptr;
34653466
SourceFile &SF = *FD->getDeclContext()->getParentSourceFile();
34663467
if (FD->isUnaryOperator()) {
34673468
if (FD->getAttrs().hasAttribute<PrefixAttr>()) {
@@ -3485,21 +3486,21 @@ void bindFuncDeclToOperator(TypeChecker &TC, FuncDecl *FD) {
34853486
// If we found both prefix and postfix, or neither prefix nor postfix,
34863487
// complain. We can't fix this situation.
34873488
if (static_cast<bool>(prefixOp) == static_cast<bool>(postfixOp)) {
3488-
TC.diagnose(FD, diag::declared_unary_op_without_attribute);
3489+
diags.diagnose(FD, diag::declared_unary_op_without_attribute);
34893490

34903491
// If we found both, point at them.
34913492
if (prefixOp) {
3492-
TC.diagnose(prefixOp, diag::unary_operator_declaration_here, false)
3493+
diags.diagnose(prefixOp, diag::unary_operator_declaration_here, false)
34933494
.fixItInsert(FD->getLoc(), "prefix ");
3494-
TC.diagnose(postfixOp, diag::unary_operator_declaration_here, true)
3495+
diags.diagnose(postfixOp, diag::unary_operator_declaration_here, true)
34953496
.fixItInsert(FD->getLoc(), "postfix ");
34963497
} else {
34973498
// FIXME: Introduce a Fix-It that adds the operator declaration?
34983499
}
34993500

35003501
// FIXME: Errors could cascade here, because name lookup for this
35013502
// operator won't find this declaration.
3502-
return;
3503+
return nullptr;
35033504
}
35043505

35053506
// We found only one operator declaration, so we know whether this
@@ -3519,29 +3520,33 @@ void bindFuncDeclToOperator(TypeChecker &TC, FuncDecl *FD) {
35193520
}
35203521

35213522
// Emit diagnostic with the Fix-It.
3522-
TC.diagnose(FD->getFuncLoc(), diag::unary_op_missing_prepos_attribute,
3523+
diags.diagnose(FD->getFuncLoc(), diag::unary_op_missing_prepos_attribute,
35233524
static_cast<bool>(postfixOp))
35243525
.fixItInsert(FD->getFuncLoc(), insertionText);
3525-
TC.diagnose(op, diag::unary_operator_declaration_here,
3526+
diags.diagnose(op, diag::unary_operator_declaration_here,
35263527
static_cast<bool>(postfixOp));
35273528
}
35283529
} else if (FD->isBinaryOperator()) {
35293530
op = SF.lookupInfixOperator(operatorName,
35303531
FD->isCascadingContextForLookup(false),
35313532
FD->getLoc());
35323533
} else {
3533-
TC.diagnose(FD, diag::invalid_arg_count_for_operator);
3534-
return;
3534+
diags.diagnose(FD, diag::invalid_arg_count_for_operator);
3535+
return nullptr;
35353536
}
35363537

35373538
if (!op) {
35383539
SourceLoc insertionLoc;
35393540
if (isa<SourceFile>(FD->getParent())) {
3540-
// Parent context is SourceFile, insertion location is start of func declaration
3541-
// or unary operator
3542-
insertionLoc = FD->isUnaryOperator() ? FD->getAttrs().getStartLoc() : FD->getStartLoc();
3541+
// Parent context is SourceFile, insertion location is start of func
3542+
// declaration or unary operator
3543+
if (FD->isUnaryOperator()) {
3544+
insertionLoc = FD->getAttrs().getStartLoc();
3545+
} else {
3546+
insertionLoc = FD->getStartLoc();
3547+
}
35433548
} else {
3544-
// Finding top-level decl context before SourceFile and inserting before it
3549+
// Find the topmost non-file decl context and insert there.
35453550
for (DeclContext *CurContext = FD->getLocalContext();
35463551
!isa<SourceFile>(CurContext);
35473552
CurContext = CurContext->getParent()) {
@@ -3552,25 +3557,28 @@ void bindFuncDeclToOperator(TypeChecker &TC, FuncDecl *FD) {
35523557
}
35533558

35543559
SmallString<128> insertion;
3555-
auto numOfParams = FD->getParameters()->size();
3556-
if (numOfParams == 1) {
3557-
if (FD->getAttrs().hasAttribute<PrefixAttr>())
3558-
insertion += "prefix operator ";
3559-
else
3560-
insertion += "postfix operator ";
3561-
} else if (numOfParams == 2) {
3562-
insertion += "infix operator ";
3563-
}
3560+
{
3561+
llvm::raw_svector_ostream str(insertion);
3562+
assert(FD->isUnaryOperator() || FD->isBinaryOperator());
3563+
if (FD->isUnaryOperator()) {
3564+
if (FD->getAttrs().hasAttribute<PrefixAttr>())
3565+
str << "prefix operator ";
3566+
else
3567+
str << "postfix operator ";
3568+
} else {
3569+
str << "infix operator ";
3570+
}
35643571

3565-
insertion += operatorName.str();
3566-
insertion += " : <# Precedence Group #>\n";
3567-
InFlightDiagnostic opDiagnostic = TC.diagnose(FD, diag::declared_operator_without_operator_decl);
3572+
str << operatorName.str() << " : <# Precedence Group #>\n";
3573+
}
3574+
InFlightDiagnostic opDiagnostic =
3575+
diags.diagnose(FD, diag::declared_operator_without_operator_decl);
35683576
if (insertionLoc.isValid())
35693577
opDiagnostic.fixItInsert(insertionLoc, insertion);
3570-
return;
3578+
return nullptr;
35713579
}
35723580

3573-
FD->setOperatorDecl(op);
3581+
return op;
35743582
}
35753583

35763584
bool swift::isMemberOperator(FuncDecl *decl, Type type) {
@@ -3868,10 +3876,9 @@ void TypeChecker::validateDecl(ValueDecl *D) {
38683876

38693877
DeclValidationRAII IBV(FD);
38703878

3871-
// Bind operator functions to the corresponding operator declaration.
3872-
if (FD->isOperator())
3873-
bindFuncDeclToOperator(*this, FD);
3874-
3879+
// Force computing the operator decl in case it emits diagnostics.
3880+
(void) FD->getOperatorDecl();
3881+
38753882
// Validate 'static'/'class' on functions in extensions.
38763883
auto StaticSpelling = FD->getStaticSpelling();
38773884
if (StaticSpelling != StaticSpellingKind::None &&

lib/Sema/TypeCheckDecl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ void validatePatternBindingEntries(TypeChecker &tc,
4242
PatternBindingDecl *binding);
4343
}
4444

45-
#endif
45+
#endif
46+

lib/Serialization/Deserialization.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3026,7 +3026,8 @@ class swift::DeclDeserializer {
30263026
if (!isAccessor) {
30273027
if (Decl *associated = MF.getDecl(associatedDeclID)) {
30283028
if (auto op = dyn_cast<OperatorDecl>(associated)) {
3029-
fn->setOperatorDecl(op);
3029+
ctx.evaluator.cacheOutput(FunctionOperatorRequest{fn},
3030+
std::move(op));
30303031

30313032
if (isa<PrefixOperatorDecl>(op))
30323033
fn->getAttrs().add(new (ctx) PrefixAttr(/*implicit*/false));

0 commit comments

Comments
 (0)