@@ -87,13 +87,16 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
87
87
// message.
88
88
struct PartialApplication {
89
89
enum : unsigned {
90
- Function,
91
90
MutatingMethod,
92
91
SuperInit,
93
92
SelfInit,
94
93
};
95
- // 'kind' before 'level' is better for code gen.
96
- unsigned kind : 3 ;
94
+ enum : unsigned {
95
+ Error,
96
+ CompatibilityWarning,
97
+ };
98
+ unsigned compatibilityWarning: 1 ;
99
+ unsigned kind : 2 ;
97
100
unsigned level : 29 ;
98
101
};
99
102
@@ -105,49 +108,18 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
105
108
~DiagnoseWalker () override {
106
109
for (auto &unapplied : InvalidPartialApplications) {
107
110
unsigned kind = unapplied.second .kind ;
108
- TC.diagnose (unapplied.first ->getLoc (),
109
- diag::partial_application_of_function_invalid,
110
- kind);
111
- }
112
- }
113
-
114
- // / If this is an application of a function that cannot be partially
115
- // / applied, arrange for us to check that it gets fully applied.
116
- void recordUnsupportedPartialApply (ApplyExpr *expr, Expr *fnExpr) {
117
-
118
- if (isa<OtherConstructorDeclRefExpr>(fnExpr)) {
119
- auto kind = expr->getArg ()->isSuperExpr ()
120
- ? PartialApplication::SuperInit
121
- : PartialApplication::SelfInit;
122
-
123
- // Partial applications of delegated initializers aren't allowed, and
124
- // don't really make sense to begin with.
125
- InvalidPartialApplications.insert ({ expr, {kind, 1 } });
126
- return ;
127
- }
128
-
129
- auto fnDeclRef = dyn_cast<DeclRefExpr>(fnExpr);
130
- if (!fnDeclRef)
131
- return ;
132
-
133
- auto fn = dyn_cast<FuncDecl>(fnDeclRef->getDecl ());
134
- if (!fn)
135
- return ;
136
-
137
- unsigned kind =
138
- fn->isInstanceMember () ? PartialApplication::MutatingMethod
139
- : PartialApplication::Function;
140
-
141
- // Functions with inout parameters cannot be partially applied.
142
- if (!expr->getArg ()->getType ()->isMaterializable ()) {
143
- // We need to apply all argument clauses.
144
- InvalidPartialApplications.insert ({
145
- fnExpr, {kind, fn->getNumParameterLists ()}
146
- });
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
+ }
147
120
}
148
121
}
149
122
150
- // / This method is called in post-order over the AST to validate that
151
123
// / methods are fully applied when they can't support partial application.
152
124
void checkInvalidPartialApplication (Expr *E) {
153
125
if (auto AE = dyn_cast<ApplyExpr>(E)) {
@@ -158,8 +130,18 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
158
130
fnExpr = dotSyntaxExpr->getRHS ();
159
131
160
132
// Check to see if this is a potentially unsupported partial
161
- // application.
162
- 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
+ }
163
145
164
146
// If this is adding a level to an active partial application, advance
165
147
// it to the next level.
@@ -173,11 +155,36 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
173
155
InvalidPartialApplications.erase (foundApplication);
174
156
if (level > 1 ) {
175
157
// We have remaining argument clauses.
176
- InvalidPartialApplications.insert ({ AE, {kind, level - 1 } });
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 }});
177
162
}
178
163
return ;
179
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 ;
180
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 ()}});
181
188
}
182
189
183
190
// Not interested in going outside a basic expression.
0 commit comments