@@ -141,6 +141,7 @@ private void InterceptCallAndAdjustArguments(
141
141
bool invokedAsExtensionMethod ,
142
142
Syntax . SimpleNameSyntax ? nameSyntax )
143
143
{
144
+ // Note: the extension method rewriter comes after the local rewriter, so we're still dealing with skeleton methods here
144
145
if ( this . _compilation . TryGetInterceptor ( nameSyntax ) is not var ( attributeLocation , interceptor ) )
145
146
{
146
147
// The call was not intercepted.
@@ -199,19 +200,23 @@ private void InterceptCallAndAdjustArguments(
199
200
// When the original call is to an instance method, and the interceptor is an extension method,
200
201
// we need to take special care to intercept with the extension method as though it is being called in reduced form.
201
202
Debug . Assert ( receiverOpt is not BoundTypeExpression || method . IsStatic ) ;
202
- var needToReduce = receiverOpt is not ( null or BoundTypeExpression ) && interceptor . IsExtensionMethod ; // Tracked by https://github.com/dotnet/roslyn/issues/76130: Test this code path with new extensions
203
- var symbolForCompare = needToReduce ? ReducedExtensionMethodSymbol . Create ( interceptor , receiverOpt ! . Type , _compilation , out _ ) : interceptor ; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : test interceptors
203
+ bool receiverIsValue = receiverOpt is not ( null or BoundTypeExpression ) ;
204
+ bool needToReduceInterceptor = receiverIsValue && interceptor . IsExtensionMethod ;
204
205
205
- if ( ! MemberSignatureComparer . InterceptorsComparer . Equals ( method , symbolForCompare ) )
206
+ MethodSymbol ? interceptorForCompare =
207
+ interceptor . GetIsNewExtensionMember ( ) && invokedAsExtensionMethod ? interceptor . TryGetCorrespondingExtensionImplementationMethod ( ) :
208
+ needToReduceInterceptor ? ReducedExtensionMethodSymbol . Create ( interceptor , receiverOpt ! . Type , _compilation , out _ ) : interceptor ;
209
+
210
+ if ( ! MemberSignatureComparer . InterceptorsComparer . Equals ( method , interceptorForCompare ) )
206
211
{
207
- this . _diagnostics . Add ( ErrorCode . ERR_InterceptorSignatureMismatch , attributeLocation , method , interceptor ) ;
212
+ this . _diagnostics . Add ( ErrorCode . ERR_InterceptorSignatureMismatch , attributeLocation , method , interceptor ) ; // Consider printing the return types as part of the compared signatures with FormattedSymbol
208
213
return ;
209
214
}
210
215
211
216
_ = SourceMemberContainerTypeSymbol . CheckValidNullableMethodOverride (
212
217
_compilation ,
213
218
method ,
214
- symbolForCompare ,
219
+ interceptorForCompare ,
215
220
_diagnostics ,
216
221
static ( diagnostics , method , interceptor , topLevel , attributeLocation ) =>
217
222
{
@@ -223,20 +228,20 @@ private void InterceptCallAndAdjustArguments(
223
228
} ,
224
229
extraArgument : attributeLocation ) ;
225
230
226
- if ( ! MemberSignatureComparer . InterceptorsStrictComparer . Equals ( method , symbolForCompare ) )
231
+ if ( ! MemberSignatureComparer . InterceptorsStrictComparer . Equals ( method , interceptorForCompare ) )
227
232
{
228
233
this . _diagnostics . Add ( ErrorCode . WRN_InterceptorSignatureMismatch , attributeLocation , method , interceptor ) ;
229
234
}
230
235
231
- method . TryGetThisParameter ( out var methodThisParameter ) ;
232
- var interceptorThisParameterForCompare = needToReduce ? interceptor . Parameters [ 0 ] :
233
- interceptor . TryGetThisParameter ( out var interceptorThisParameter ) ? interceptorThisParameter : null ;
234
- switch ( methodThisParameter , interceptorThisParameterForCompare )
236
+ ParameterSymbol ? methodReceiverParameter = getReceiverParameter ( method , classicExtensionNotInvokedAsStatic : invokedAsExtensionMethod ) ;
237
+ ParameterSymbol ? interceptorThisParameterForCompare = getReceiverParameter ( interceptor , classicExtensionNotInvokedAsStatic : invokedAsExtensionMethod || needToReduceInterceptor ) ;
238
+
239
+ switch ( methodReceiverParameter , interceptorThisParameterForCompare )
235
240
{
236
241
case ( not null , null ) :
237
- case ( not null , not null ) when ! methodThisParameter . Type . Equals ( interceptorThisParameterForCompare . Type , TypeCompareKind . ObliviousNullableModifierMatchesAny )
238
- || methodThisParameter . RefKind != interceptorThisParameterForCompare . RefKind :
239
- this . _diagnostics . Add ( ErrorCode . ERR_InterceptorMustHaveMatchingThisParameter , attributeLocation , methodThisParameter , method ) ;
242
+ case ( not null , not null ) when ! methodReceiverParameter . Type . Equals ( interceptorThisParameterForCompare . Type , TypeCompareKind . ObliviousNullableModifierMatchesAny )
243
+ || methodReceiverParameter . RefKind != interceptorThisParameterForCompare . RefKind :
244
+ this . _diagnostics . Add ( ErrorCode . ERR_InterceptorMustHaveMatchingThisParameter , attributeLocation , methodReceiverParameter , method ) ;
240
245
return ;
241
246
case ( null , not null ) :
242
247
this . _diagnostics . Add ( ErrorCode . ERR_InterceptorMustNotHaveThisParameter , attributeLocation , method ) ;
@@ -245,7 +250,7 @@ private void InterceptCallAndAdjustArguments(
245
250
break ;
246
251
}
247
252
248
- if ( invokedAsExtensionMethod && interceptor . IsStatic && ! interceptor . IsExtensionMethod ) // Tracked by https://github.com/dotnet/roslyn/issues/76130: Test this code path with new extensions
253
+ if ( invokedAsExtensionMethod && interceptor . IsStatic && ! interceptor . IsExtensionMethod )
249
254
{
250
255
// Special case when intercepting an extension method call in reduced form with a non-extension.
251
256
this . _diagnostics . Add ( ErrorCode . ERR_InterceptorMustHaveMatchingThisParameter , attributeLocation , method . Parameters [ 0 ] , method ) ;
@@ -254,7 +259,7 @@ private void InterceptCallAndAdjustArguments(
254
259
255
260
if ( SourceMemberContainerTypeSymbol . CheckValidScopedOverride (
256
261
method ,
257
- symbolForCompare ,
262
+ interceptorForCompare ,
258
263
this . _diagnostics ,
259
264
static ( diagnostics , method , symbolForCompare , implementingParameter , blameAttributes , attributeLocation ) =>
260
265
{
@@ -268,20 +273,21 @@ private void InterceptCallAndAdjustArguments(
268
273
return ;
269
274
}
270
275
271
- if ( needToReduce )
276
+ if ( receiverIsValue && ( interceptor . IsExtensionMethod || interceptor . GetIsNewExtensionMember ( ) ) )
272
277
{
273
- Debug . Assert ( methodThisParameter is not null ) ;
278
+ Debug . Assert ( methodReceiverParameter is not null ) ;
274
279
Debug . Assert ( receiverOpt ? . Type is not null ) ;
275
280
276
281
// Usually we expect the receiver to already be converted to the this parameter type.
277
282
// However, in the case of a non-reference type receiver, where the this parameter is some base reference type,
278
283
// for example a struct type and System.ValueType respectively, we need to convert the receiver to parameter type,
279
284
// because we can't use the same `.constrained` calling pattern here which we would have used for an instance method receiver.
280
- Debug . Assert ( receiverOpt . Type . Equals ( interceptor . Parameters [ 0 ] . Type , TypeCompareKind . AllIgnoreOptions )
281
- || ( ! receiverOpt . Type . IsReferenceType && interceptor . Parameters [ 0 ] . Type . IsReferenceType ) ) ;
282
- receiverOpt = MakeConversionNode ( receiverOpt , interceptor . Parameters [ 0 ] . Type , @checked : false , markAsChecked : true ) ;
285
+ Debug . Assert ( receiverOpt . Type . Equals ( interceptorThisParameterForCompare ! . Type , TypeCompareKind . AllIgnoreOptions )
286
+ || ( ! receiverOpt . Type . IsReferenceType && interceptorThisParameterForCompare . Type . IsReferenceType ) ) ;
287
+
288
+ receiverOpt = MakeConversionNode ( receiverOpt , interceptorThisParameterForCompare . Type , @checked : false , markAsChecked : true ) ;
283
289
284
- var thisRefKind = methodThisParameter . RefKind ;
290
+ var thisRefKind = methodReceiverParameter . RefKind ;
285
291
// Instance call receivers can be implicitly captured to temps in the emit layer, but not static call arguments
286
292
// Therefore we may need to explicitly store the receiver to temp here.
287
293
if ( thisRefKind != RefKind . None
@@ -297,24 +303,49 @@ private void InterceptCallAndAdjustArguments(
297
303
receiverOpt = _factory . Sequence ( locals : [ ] , sideEffects : [ assignmentToTemp ] , receiverTemp ) ;
298
304
}
299
305
300
- arguments = arguments . Insert ( 0 , receiverOpt ) ;
301
- receiverOpt = null ;
302
-
303
- // CodeGenerator.EmitArguments requires that we have a fully-filled-out argumentRefKindsOpt for any ref/in/out arguments.
304
- if ( argumentRefKindsOpt . IsDefault && thisRefKind != RefKind . None )
306
+ if ( interceptor . IsExtensionMethod )
305
307
{
306
- argumentRefKindsOpt = method . Parameters . SelectAsArray ( static param => param . RefKind ) ;
307
- }
308
+ arguments = arguments . Insert ( 0 , receiverOpt ) ;
309
+ receiverOpt = null ;
308
310
309
- if ( ! argumentRefKindsOpt . IsDefault )
310
- {
311
- argumentRefKindsOpt = argumentRefKindsOpt . Insert ( 0 , thisRefKind ) ;
311
+ // CodeGenerator.EmitArguments requires that we have a fully-filled-out argumentRefKindsOpt for any ref/in/out arguments.
312
+ if ( argumentRefKindsOpt . IsDefault && thisRefKind != RefKind . None )
313
+ {
314
+ argumentRefKindsOpt = method . Parameters . SelectAsArray ( static param => param . RefKind ) ;
315
+ }
316
+
317
+ if ( ! argumentRefKindsOpt . IsDefault )
318
+ {
319
+ argumentRefKindsOpt = argumentRefKindsOpt . Insert ( 0 , thisRefKind ) ;
320
+ }
312
321
}
313
322
}
314
323
315
324
method = interceptor ;
316
325
317
326
return ;
327
+
328
+ static ParameterSymbol ? getReceiverParameter ( MethodSymbol method , bool classicExtensionNotInvokedAsStatic )
329
+ {
330
+ if ( method . IsExtensionMethod && classicExtensionNotInvokedAsStatic )
331
+ {
332
+ return method . Parameters [ 0 ] ;
333
+ }
334
+
335
+ if ( method . GetIsNewExtensionMember ( ) )
336
+ {
337
+ if ( method . IsStatic )
338
+ {
339
+ return null ;
340
+ }
341
+
342
+ Debug . Assert ( method . ContainingType . ExtensionParameter is not null ) ;
343
+ return method . ContainingType . ExtensionParameter ;
344
+ }
345
+
346
+ method . TryGetThisParameter ( out ParameterSymbol ? methodReceiverParameter ) ;
347
+ return methodReceiverParameter ;
348
+ }
318
349
}
319
350
320
351
public override BoundNode VisitCall ( BoundCall node )
0 commit comments