@@ -86,14 +86,18 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
86
86
// Selector for the partial_application_of_function_invalid diagnostic
87
87
// message.
88
88
struct PartialApplication {
89
- unsigned level : 29 ;
90
89
enum : unsigned {
91
- Function,
92
90
MutatingMethod,
93
91
SuperInit,
94
92
SelfInit,
95
93
};
96
- unsigned kind : 3 ;
94
+ enum : unsigned {
95
+ Error,
96
+ CompatibilityWarning,
97
+ };
98
+ unsigned compatibilityWarning: 1 ;
99
+ unsigned kind : 2 ;
100
+ unsigned level : 29 ;
97
101
};
98
102
99
103
// Partial applications of functions that are not permitted. This is
@@ -104,49 +108,18 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
104
108
~DiagnoseWalker () override {
105
109
for (auto &unapplied : InvalidPartialApplications) {
106
110
unsigned kind = unapplied.second .kind ;
107
- TC.diagnose (unapplied.first ->getLoc (),
108
- diag::partial_application_of_function_invalid,
109
- kind);
110
- }
111
- }
112
-
113
- // / If this is an application of a function that cannot be partially
114
- // / applied, arrange for us to check that it gets fully applied.
115
- void recordUnsupportedPartialApply (ApplyExpr *expr, Expr *fnExpr) {
116
-
117
- if (isa<OtherConstructorDeclRefExpr>(fnExpr)) {
118
- auto kind = expr->getArg ()->isSuperExpr ()
119
- ? PartialApplication::SuperInit
120
- : PartialApplication::SelfInit;
121
-
122
- // Partial applications of delegated initializers aren't allowed, and
123
- // don't really make sense to begin with.
124
- InvalidPartialApplications.insert ({ expr, {1 , kind} });
125
- return ;
126
- }
127
-
128
- auto fnDeclRef = dyn_cast<DeclRefExpr>(fnExpr);
129
- if (!fnDeclRef)
130
- return ;
131
-
132
- auto fn = dyn_cast<FuncDecl>(fnDeclRef->getDecl ());
133
- if (!fn)
134
- return ;
135
-
136
- unsigned kind =
137
- fn->isInstanceMember () ? PartialApplication::MutatingMethod
138
- : PartialApplication::Function;
139
-
140
- // Functions with inout parameters cannot be partially applied.
141
- if (!expr->getArg ()->getType ()->isMaterializable ()) {
142
- // We need to apply all argument clauses.
143
- InvalidPartialApplications.insert ({
144
- fnExpr, {fn->getNumParameterLists (), kind}
145
- });
111
+ if (unapplied.second .compatibilityWarning ) {
112
+ TC.diagnose (unapplied.first ->getLoc (),
113
+ diag::partial_application_of_function_invalid_swift4,
114
+ kind);
115
+ } else {
116
+ TC.diagnose (unapplied.first ->getLoc (),
117
+ diag::partial_application_of_function_invalid,
118
+ kind);
119
+ }
146
120
}
147
121
}
148
122
149
- // / This method is called in post-order over the AST to validate that
150
123
// / methods are fully applied when they can't support partial application.
151
124
void checkInvalidPartialApplication (Expr *E) {
152
125
if (auto AE = dyn_cast<ApplyExpr>(E)) {
@@ -157,8 +130,18 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
157
130
fnExpr = dotSyntaxExpr->getRHS ();
158
131
159
132
// Check to see if this is a potentially unsupported partial
160
- // application.
161
- recordUnsupportedPartialApply (AE, fnExpr);
133
+ // application of a constructor delegation.
134
+ if (isa<OtherConstructorDeclRefExpr>(fnExpr)) {
135
+ auto kind = AE->getArg ()->isSuperExpr ()
136
+ ? PartialApplication::SuperInit
137
+ : PartialApplication::SelfInit;
138
+
139
+ // Partial applications of delegated initializers aren't allowed, and
140
+ // don't really make sense to begin with.
141
+ InvalidPartialApplications.insert (
142
+ {E, {PartialApplication::Error, kind, 1 }});
143
+ return ;
144
+ }
162
145
163
146
// If this is adding a level to an active partial application, advance
164
147
// it to the next level.
@@ -172,11 +155,36 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
172
155
InvalidPartialApplications.erase (foundApplication);
173
156
if (level > 1 ) {
174
157
// We have remaining argument clauses.
175
- InvalidPartialApplications.insert ({ AE, {level - 1 , kind} });
158
+ // Partial applications were always diagnosed in Swift 4 and before,
159
+ // so there's no need to preserve the compatibility warning bit.
160
+ InvalidPartialApplications.insert (
161
+ {AE, {PartialApplication::Error, kind, level - 1 }});
176
162
}
177
163
return ;
178
164
}
165
+
166
+ // / If this is a reference to a mutating method, it cannot be partially
167
+ // / applied or even referenced without full application, so arrange for
168
+ // / us to check that it gets fully applied.
169
+ auto fnDeclRef = dyn_cast<DeclRefExpr>(E);
170
+ if (!fnDeclRef)
171
+ return ;
172
+
173
+ auto fn = dyn_cast<FuncDecl>(fnDeclRef->getDecl ());
174
+ if (!fn || !fn->isInstanceMember () || !fn->isMutating ())
175
+ return ;
179
176
177
+ // Swift 4 and earlier failed to diagnose a reference to a mutating method
178
+ // without any applications at all, which would get miscompiled into a
179
+ // function with undefined behavior. Warn for source compatibility.
180
+ auto errorBehavior = TC.Context .LangOpts .isSwiftVersionAtLeast (5 )
181
+ ? PartialApplication::Error
182
+ : PartialApplication::CompatibilityWarning;
183
+
184
+ InvalidPartialApplications.insert (
185
+ {fnDeclRef, {errorBehavior,
186
+ PartialApplication::MutatingMethod,
187
+ fn->getNumParameterLists ()}});
180
188
}
181
189
182
190
// Not interested in going outside a basic expression.
0 commit comments