Skip to content

Commit 004db7c

Browse files
[Sema] Add param indicate diagnose or not in lookupPrecedenceGroupForInfixOperator
1 parent 7b9d4e6 commit 004db7c

File tree

4 files changed

+41
-17
lines changed

4 files changed

+41
-17
lines changed

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8110,7 +8110,8 @@ bool swift::exprNeedsParensInsideFollowingOperator(
81108110
DeclContext *DC, Expr *expr,
81118111
PrecedenceGroupDecl *followingPG) {
81128112
if (expr->isInfixOperator()) {
8113-
auto exprPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC, expr);
8113+
auto exprPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(
8114+
DC, expr, /*diagnose=*/false);
81148115
if (!exprPG) return true;
81158116

81168117
return DC->getASTContext().associateInfixOperators(exprPG, followingPG)
@@ -8160,8 +8161,8 @@ bool swift::exprNeedsParensOutsideFollowingOperator(
81608161
return false;
81618162

81628163
if (parent->isInfixOperator()) {
8163-
auto parentPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC,
8164-
parent);
8164+
auto parentPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(
8165+
DC, parent, /*diagnose=*/false);
81658166
if (!parentPG) return true;
81668167

81678168
// If the index is 0, this is on the LHS of the parent.

lib/Sema/TypeCheckExpr.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,18 +107,22 @@ Expr *TypeChecker::substituteInputSugarTypeForResult(ApplyExpr *E) {
107107
static PrecedenceGroupDecl *lookupPrecedenceGroupForOperator(DeclContext *DC,
108108
Identifier name,
109109
SourceLoc loc) {
110-
auto *op = DC->lookupInfixOperator(name).getSingleOrDiagnose(loc);
110+
auto result = DC->lookupInfixOperator(name);
111+
auto *op =
112+
loc.isValid() ? result.getSingleOrDiagnose(loc) : result.getSingle();
111113
return op ? op->getPrecedenceGroup() : nullptr;
112114
}
113115

114116
PrecedenceGroupDecl *
115-
TypeChecker::lookupPrecedenceGroupForInfixOperator(DeclContext *DC, Expr *E) {
117+
TypeChecker::lookupPrecedenceGroupForInfixOperator(DeclContext *DC, Expr *E,
118+
bool diagnose) {
116119
/// Look up the builtin precedence group with the given name.
117120

118121
auto getBuiltinPrecedenceGroup = [&](DeclContext *DC, Identifier name,
119122
SourceLoc loc) -> PrecedenceGroupDecl * {
120123
auto groups = TypeChecker::lookupPrecedenceGroup(DC, name, loc);
121-
return groups.getSingleOrDiagnose(loc, /*forBuiltin*/ true);
124+
return diagnose ? groups.getSingleOrDiagnose(loc, /*forBuiltin*/ true)
125+
: groups.getSingle();
122126
};
123127

124128
auto &Context = DC->getASTContext();
@@ -142,12 +146,14 @@ TypeChecker::lookupPrecedenceGroupForInfixOperator(DeclContext *DC, Expr *E) {
142146

143147
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
144148
Identifier name = DRE->getDecl()->getBaseIdentifier();
145-
return lookupPrecedenceGroupForOperator(DC, name, DRE->getLoc());
149+
return lookupPrecedenceGroupForOperator(
150+
DC, name, diagnose ? DRE->getLoc() : SourceLoc());
146151
}
147152

148153
if (auto *OO = dyn_cast<OverloadedDeclRefExpr>(E)) {
149154
Identifier name = OO->getDecls()[0]->getBaseIdentifier();
150-
return lookupPrecedenceGroupForOperator(DC, name, OO->getLoc());
155+
return lookupPrecedenceGroupForOperator(
156+
DC, name, diagnose ? OO->getLoc() : SourceLoc());
151157
}
152158

153159
if (auto arrowExpr = dyn_cast<ArrowExpr>(E)) {
@@ -159,21 +165,23 @@ TypeChecker::lookupPrecedenceGroupForInfixOperator(DeclContext *DC, Expr *E) {
159165
// An already-folded binary operator comes up for non-primary use cases
160166
// of this function.
161167
if (auto binaryExpr = dyn_cast<BinaryExpr>(E)) {
162-
return lookupPrecedenceGroupForInfixOperator(DC, binaryExpr->getFn());
168+
return lookupPrecedenceGroupForInfixOperator(DC, binaryExpr->getFn(),
169+
diagnose);
163170
}
164171

165172
if (auto *DSCE = dyn_cast<DotSyntaxCallExpr>(E)) {
166-
return lookupPrecedenceGroupForInfixOperator(DC, DSCE->getFn());
173+
return lookupPrecedenceGroupForInfixOperator(DC, DSCE->getFn(), diagnose);
167174
}
168175

169176
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
170177
Identifier name = MRE->getDecl().getDecl()->getBaseIdentifier();
171-
return lookupPrecedenceGroupForOperator(DC, name, MRE->getLoc());
178+
return lookupPrecedenceGroupForOperator(
179+
DC, name, diagnose ? MRE->getLoc() : SourceLoc());
172180
}
173181

174182
// If E is already an ErrorExpr, then we've diagnosed it as invalid already,
175183
// otherwise emit an error.
176-
if (!isa<ErrorExpr>(E))
184+
if (diagnose && !isa<ErrorExpr>(E))
177185
Context.Diags.diagnose(E->getLoc(), diag::unknown_binop);
178186

179187
return nullptr;
@@ -203,7 +211,7 @@ Expr *TypeChecker::findLHS(DeclContext *DC, Expr *E, Identifier name) {
203211
continue;
204212
}
205213

206-
auto left = lookupPrecedenceGroupForInfixOperator(DC, E);
214+
auto left = lookupPrecedenceGroupForInfixOperator(DC, E, /*diagnose=*/true);
207215
if (!left)
208216
// LHS is not binary expression.
209217
return E;
@@ -425,7 +433,8 @@ static Expr *foldSequence(DeclContext *DC,
425433
Expr *op = S[0];
426434

427435
// If the operator's precedence is lower than the minimum, stop here.
428-
auto opPrecedence = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC, op);
436+
auto opPrecedence = TypeChecker::lookupPrecedenceGroupForInfixOperator(
437+
DC, op, /*diagnose=*/true);
429438
if (!precedenceBound.shouldConsider(opPrecedence))
430439
return {nullptr, nullptr};
431440
return {op, opPrecedence};
@@ -457,7 +466,8 @@ static Expr *foldSequence(DeclContext *DC,
457466
}
458467

459468
// Pull out the next binary operator.
460-
Op op2{ S[0], TypeChecker::lookupPrecedenceGroupForInfixOperator(DC, S[0]) };
469+
Op op2{S[0], TypeChecker::lookupPrecedenceGroupForInfixOperator(
470+
DC, S[0], /*diagnose=*/true)};
461471

462472
// If the second operator's precedence is lower than the
463473
// precedence bound, break out of the loop.

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -905,8 +905,8 @@ lookupMemberType(DeclContext *dc, Type type, DeclNameRef name,
905905

906906
/// Given an expression that's known to be an infix operator,
907907
/// look up its precedence group.
908-
PrecedenceGroupDecl *lookupPrecedenceGroupForInfixOperator(DeclContext *dc,
909-
Expr *op);
908+
PrecedenceGroupDecl *
909+
lookupPrecedenceGroupForInfixOperator(DeclContext *dc, Expr *op, bool diagnose);
910910

911911
PrecedenceGroupLookupResult
912912
lookupPrecedenceGroup(DeclContext *dc, Identifier name, SourceLoc nameLoc);

test/Constraints/operator.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,16 @@ do {
314314
let number = 1
315315
let test = true || number == .First.rawValue // expected-error {{type 'Int' has no member 'First'}}
316316
}
317+
318+
// https://github.com/apple/swift/issues/60954
319+
enum I60954 {
320+
// expected-error@+1{{operator implementation without matching operator declaration}}
321+
func ?= (pattern: I60954?, version: Self) { // expected-error{{operator '?=' declared in type 'I60954' must be 'static'}}
322+
// expected-error@+2{{operator is not a known binary operator}}
323+
// expected-error@+1{{initializer 'init(_:)' requires that 'I60954' conform to 'StringProtocol'}}
324+
pattern ?= .init(version) // expected-error{{value of optional type 'I60954?' must be unwrapped to a value of type 'I60954'}}
325+
// expected-note@-1{{coalesce using '??' to provide a default when the optional value contains 'nil'}}
326+
// expected-note@-2{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
327+
}
328+
init?<S>(_ string: S) where S: StringProtocol {} // expected-note{{where 'S' = 'I60954'}}
329+
}

0 commit comments

Comments
 (0)