From 60507581a240f103b55473e324a97ba541270566 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Thu, 20 Mar 2025 10:33:15 -0700 Subject: [PATCH 1/5] Implement scoping and shadowing rules for extension parameter and type parameters See https://github.com/dotnet/csharplang/pull/9229 (commit 9) --- .../BinderFactory.BinderFactoryVisitor.cs | 21 +- .../Portable/Binder/Binder_Expressions.cs | 8 + .../Portable/Binder/Binder_NameConflicts.cs | 37 +- .../CSharp/Portable/Binder/InMethodBinder.cs | 22 +- .../Binder/WithClassTypeParametersBinder.cs | 14 + .../Binder/WithExtensionParameterBinder.cs | 54 + .../Binder/WithMethodTypeParametersBinder.cs | 3 +- .../Binder/WithTypeParametersBinder.cs | 1 - .../CSharp/Portable/CSharpResources.resx | 24 + .../CSharp/Portable/Errors/ErrorCode.cs | 8 + .../CSharp/Portable/Errors/ErrorFacts.cs | 8 + .../Extensions/SynthesizedExtensionMarker.cs | 10 +- .../Symbols/Source/ParameterHelpers.cs | 16 +- .../Source/SourceMemberContainerSymbol.cs | 23 +- .../Source/SourceNamedTypeSymbol_Extension.cs | 69 +- .../Source/SourceOrdinaryMethodSymbol.cs | 33 +- .../Symbols/Source/SourcePropertySymbol.cs | 13 + .../Portable/Symbols/TypeSymbolExtensions.cs | 21 +- .../Portable/xlf/CSharpResources.cs.xlf | 40 + .../Portable/xlf/CSharpResources.de.xlf | 40 + .../Portable/xlf/CSharpResources.es.xlf | 40 + .../Portable/xlf/CSharpResources.fr.xlf | 40 + .../Portable/xlf/CSharpResources.it.xlf | 40 + .../Portable/xlf/CSharpResources.ja.xlf | 40 + .../Portable/xlf/CSharpResources.ko.xlf | 40 + .../Portable/xlf/CSharpResources.pl.xlf | 40 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 40 + .../Portable/xlf/CSharpResources.ru.xlf | 40 + .../Portable/xlf/CSharpResources.tr.xlf | 40 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 40 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 40 + .../Test/Emit3/Semantics/ExtensionTests.cs | 1656 ++++++++++++++++- .../Semantics/InheritanceBindingTests.cs | 4 +- 33 files changed, 2436 insertions(+), 129 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index 7a8e1e6a9e876..2e82ab6e0a8b5 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -183,7 +183,6 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl { method = method ?? GetMethodSymbol(methodDecl, resultBinder); isIteratorBody = method.IsIterator; - resultBinder = WithExtensionReceiverParameterBinderIfNecessary(resultBinder, method); resultBinder = new InMethodBinder(method, resultBinder); } @@ -194,19 +193,6 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl return resultBinder; } - private static Binder WithExtensionReceiverParameterBinderIfNecessary(Binder resultBinder, MethodSymbol method) - { - if (method is { IsStatic: false, ContainingType: SourceNamedTypeSymbol { IsExtension: true, ExtensionParameter: { } parameter } }) - { - // PROTOTYPE: Depending on whether we consider method parameters and receiver parameter in the same scope and - // what are the name conflict/shadowing rules, we might consider to adjust behavior of InMethodBinder instead. - // If we decide to keep usage of WithParametersBinder, we might want to update XML doc comment for it. - return new WithParametersBinder([parameter], resultBinder); - } - - return resultBinder; - } - public override Binder VisitConstructorDeclaration(ConstructorDeclarationSyntax parent) { // If the position isn't in the scope of the method, then proceed to the parent syntax node. @@ -327,7 +313,6 @@ public override Binder VisitAccessorDeclaration(AccessorDeclarationSyntax parent if ((object)accessor != null) { - resultBinder = WithExtensionReceiverParameterBinderIfNecessary(resultBinder, accessor); resultBinder = new InMethodBinder(accessor, resultBinder); resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary( @@ -437,7 +422,6 @@ private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSynta // `isIteratorBody` to `SetOrClearUnsafeRegionIfNecessary` above. Debug.Assert(!accessor.IsIterator); - resultBinder = WithExtensionReceiverParameterBinderIfNecessary(resultBinder, accessor); resultBinder = new InMethodBinder(accessor, resultBinder); } @@ -797,6 +781,11 @@ internal Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent, NodeUsage { resultBinder = new WithClassTypeParametersBinder(typeSymbol, resultBinder); } + + if (typeSymbol.IsExtension) + { + resultBinder = new WithExtensionParameterBinder(typeSymbol, resultBinder); + } } } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 4459ac198360d..2fd89abcf810f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -2116,6 +2116,14 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Bind { Error(diagnostics, ErrorCode.ERR_InvalidPrimaryConstructorParameterReference, node, parameter); } + else if (parameter.ContainingSymbol is NamedTypeSymbol { IsExtension: true } && + (InParameterDefaultValue || InAttributeArgument || + this.ContainingMember() is not { Kind: not SymbolKind.NamedType, IsStatic: false } || // We are not in an instance member + (object)this.ContainingMember().ContainingSymbol != parameter.ContainingSymbol) && + !IsInsideNameof) + { + Error(diagnostics, ErrorCode.ERR_InvalidExtensionParameterReference, node, parameter); + } else { // Records never capture parameters within the type diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs b/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs index a4bb61a86fcff..a270498a380c5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs @@ -30,10 +30,10 @@ internal void ValidateParameterNameConflicts( bool allowShadowingNames, BindingDiagnosticBag diagnostics) { - PooledHashSet? tpNames = null; + PooledDictionary? tpNames = null; if (!typeParameters.IsDefaultOrEmpty) { - tpNames = PooledHashSet.GetInstance(); + tpNames = PooledDictionary.GetInstance(); foreach (var tp in typeParameters) { var name = tp.Name; @@ -42,7 +42,7 @@ internal void ValidateParameterNameConflicts( continue; } - if (!tpNames.Add(name)) + if (!tpNames.TryAdd(name, tp)) { // Type parameter declaration name conflicts are detected elsewhere } @@ -65,16 +65,37 @@ internal void ValidateParameterNameConflicts( continue; } - if (tpNames != null && tpNames.Contains(name)) + if (tpNames != null && tpNames.TryGetValue(name, out TypeParameterSymbol? tp)) { - // CS0412: 'X': a parameter or local variable cannot have the same name as a method type parameter - diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, GetLocation(p), name); + if (tp.ContainingSymbol is NamedTypeSymbol { IsExtension: true }) + { + if (p.ContainingSymbol != (object)tp.ContainingSymbol) + { + diagnostics.Add(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, GetLocation(p), name); + } + } + else if (p.ContainingSymbol is NamedTypeSymbol { IsExtension: true }) + { + diagnostics.Add(ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter, tp.GetFirstLocationOrNone(), name); + } + else + { + // CS0412: 'X': a parameter or local variable cannot have the same name as a method type parameter + diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, GetLocation(p), name); + } } if (!pNames.Add(name)) { - // The parameter name '{0}' is a duplicate - diagnostics.Add(ErrorCode.ERR_DuplicateParamName, GetLocation(p), name); + if (parameters[0] is { ContainingSymbol: NamedTypeSymbol { IsExtension: true }, Name: var receiverName } && receiverName == name) + { + diagnostics.Add(ErrorCode.ERR_LocalSameNameAsExtensionParameter, GetLocation(p), name); + } + else + { + // The parameter name '{0}' is a duplicate + diagnostics.Add(ErrorCode.ERR_DuplicateParamName, GetLocation(p), name); + } } else if (!allowShadowingNames) { diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index c2e47a7daeadd..b835e700c620f 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -292,8 +292,16 @@ private static bool ReportConflictWithParameter(Symbol parameter, Symbol newSymb { case SymbolKind.Parameter: case SymbolKind.Local: - // CS0412: '{0}': a parameter, local variable, or local function cannot have the same name as a method type parameter - diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, newLocation, name); + if (parameter.ContainingSymbol is NamedTypeSymbol { IsExtension: true }) + { + diagnostics.Add(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, newLocation, name); + } + else + { + // CS0412: '{0}': a parameter, local variable, or local function cannot have the same name as a method type parameter + diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, newLocation, name); + } + return true; case SymbolKind.Method: @@ -324,6 +332,16 @@ internal override bool EnsureSingleDefinition(Symbol symbol, string name, Locati var parameters = _methodSymbol.Parameters; var typeParameters = _methodSymbol.TypeParameters; + if (_methodSymbol.GetIsNewExtensionMember()) + { + typeParameters = _methodSymbol.ContainingType.TypeParameters.Concat(typeParameters); + + if (_methodSymbol.ContainingType.ExtensionParameter is { Name: not "" } receiver) + { + parameters = parameters.Insert(0, receiver); + } + } + if (parameters.IsEmpty && typeParameters.IsEmpty) { return false; diff --git a/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs index a073d882d9a94..fd1a7d0f2c3aa 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs @@ -62,5 +62,19 @@ internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo resu } } } + + protected override LookupOptions LookupMask + { + get + { + if (_namedType.IsExtension) + { + // Extension type parameters should get the same treatment as method type parameters + return WithMethodTypeParametersBinder.MethodTypeParameterLookupMask; + } + + return base.LookupMask; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs new file mode 100644 index 0000000000000..e25cfc8b8f993 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp +{ + /// + /// Binder used to place extension parameter, if any, in scope. + /// + internal sealed class WithExtensionParameterBinder : Binder + { + private readonly NamedTypeSymbol _type; + + internal WithExtensionParameterBinder(NamedTypeSymbol type, Binder next) + : base(next) + { + _type = type; + } + + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + { + if (options.CanConsiderMembers()) + { + if (_type.ExtensionParameter is { Name: not "" } parameter && + originalBinder.CanAddLookupSymbolInfo(parameter, options, result, null)) + { + result.AddSymbol(parameter, parameter.Name, 0); + } + } + } + + internal override void LookupSymbolsInSingleBinder( + LookupResult result, string name, int arity, ConsList basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref CompoundUseSiteInfo useSiteInfo) + { + Debug.Assert(result.IsClear); + + if ((options & (LookupOptions.NamespaceAliasesOnly | LookupOptions.NamespacesOrTypesOnly)) != 0) + { + return; + } + + if (_type.ExtensionParameter is { Name: not "" } parameter && parameter.Name == name) + { + result.MergeEqual(originalBinder.CheckViability(parameter, arity, options, null, diagnose, ref useSiteInfo)); + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs index f72176050939d..5d3142da798a1 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs @@ -15,6 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// internal sealed class WithMethodTypeParametersBinder : WithTypeParametersBinder { + internal const LookupOptions MethodTypeParameterLookupMask = LookupOptions.NamespaceAliasesOnly | LookupOptions.MustNotBeMethodTypeParameter; private readonly MethodSymbol _methodSymbol; private MultiDictionary _lazyTypeParameterMap; @@ -57,7 +58,7 @@ protected override LookupOptions LookupMask { get { - return LookupOptions.NamespaceAliasesOnly | LookupOptions.MustNotBeMethodTypeParameter; + return MethodTypeParameterLookupMask; } } diff --git a/src/Compilers/CSharp/Portable/Binder/WithTypeParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithTypeParametersBinder.cs index f44ecf90aa85e..62e6cb17b378b 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithTypeParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithTypeParametersBinder.cs @@ -21,7 +21,6 @@ internal WithTypeParametersBinder(Binder next) // TODO: Change this to a data structure that won't allocate enumerators protected abstract MultiDictionary TypeParameterMap { get; } - // This is only overridden by WithMethodTypeParametersBinder. protected virtual LookupOptions LookupMask { get diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 0eae7ec0a076e..0b0f41ef99b6e 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -8092,4 +8092,28 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' does not contain a definition for '{1}' and no accessible extension member '{1}' for receiver of type '{0}' could be found (are you missing a using directive or an assembly reference?) + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + + Type parameter '{0}' has the same name as an extension container type parameter + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + Type parameter '{0}' has the same name as an extension parameter + + + Cannot use extension parameter '{0}' in this context. + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index dc367e20e694e..5402223ec00ce 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2376,6 +2376,14 @@ internal enum ErrorCode ERR_ExtensionParameterDisallowsDefaultValue = 9503, ERR_ReceiverParameterOnlyOne = 9504, ERR_ExtensionResolutionFailed = 9505, + ERR_ReceiverParameterSameNameAsTypeParameter = 9506, + ERR_LocalSameNameAsExtensionTypeParameter = 9507, + ERR_TypeParameterSameNameAsExtensionTypeParameter = 9508, + ERR_LocalSameNameAsExtensionParameter = 9509, + ERR_ValueParameterSameNameAsExtensionParameter = 9510, + ERR_TypeParameterSameNameAsExtensionParameter = 9511, + ERR_InvalidExtensionParameterReference = 9512, + ERR_ValueParameterSameNameAsExtensionTypeParameter = 9513, // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index d3b443022a102..d6321178813c1 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2493,6 +2493,14 @@ or ErrorCode.ERR_BadExtensionContainingType or ErrorCode.ERR_ExtensionParameterDisallowsDefaultValue or ErrorCode.ERR_ReceiverParameterOnlyOne or ErrorCode.ERR_ExtensionResolutionFailed + or ErrorCode.ERR_ReceiverParameterSameNameAsTypeParameter + or ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter + or ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter + or ErrorCode.ERR_LocalSameNameAsExtensionParameter + or ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter + or ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter + or ErrorCode.ERR_InvalidExtensionParameterReference + or ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter => false, }; #pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. diff --git a/src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs b/src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs index c2059bcb75e51..7618a206e729e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs @@ -72,7 +72,15 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray p.Name == name, name)) + { + diagnostics.Add(ErrorCode.ERR_ReceiverParameterSameNameAsTypeParameter, parameter.GetFirstLocation(), name); + } + + return parameter; } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index 178f502540ec8..79b0a9bc5c6d2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -210,13 +210,25 @@ private static ImmutableArray MakeParameters); + []; + + ImmutableArray parametersForNameConflict = parameters.Cast(); + + if (owner.GetIsNewExtensionMember()) + { + typeParameters = owner.ContainingType.TypeParameters.Concat(typeParameters); + + if (owner.ContainingType.ExtensionParameter is { Name: not "" } receiver) + { + parametersForNameConflict = parametersForNameConflict.Insert(0, receiver); + } + } Debug.Assert(methodOwner?.MethodKind != MethodKind.LambdaMethod); bool allowShadowingNames = withTypeParametersBinder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions) && methodOwner?.MethodKind == MethodKind.LocalFunction; - withTypeParametersBinder.ValidateParameterNameConflicts(typeParameters, parameters.Cast(), allowShadowingNames, diagnostics); + withTypeParametersBinder.ValidateParameterNameConflicts(typeParameters, parametersForNameConflict, allowShadowingNames, diagnostics); } return parameters; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 2d032c9331d82..84df2fa40edd1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -2242,7 +2242,7 @@ private void CheckIndexerNameConflicts(BindingDiagnosticBag diagnostics, Diction // Also check for collisions with type parameters, which aren't in the member map. // NOTE: Accessors have normal names and are handled in CheckTypeParameterNameConflicts. - if (typeParameterNames != null) + if (typeParameterNames != null && !IsExtension) { string indexerName = indexer.MetadataName; if (typeParameterNames.Contains(indexerName)) @@ -2319,9 +2319,9 @@ private void CheckSpecialMemberErrors(BindingDiagnosticBag diagnostics) private void CheckTypeParameterNameConflicts(BindingDiagnosticBag diagnostics) { - if (this.TypeKind == TypeKind.Delegate) + if (this.TypeKind is TypeKind.Delegate or TypeKind.Extension) { - // Delegates do not have conflicts between their type parameter + // Delegates and extensions do not have conflicts between their type parameter // names and their methods; it is legal (though odd) to say // delegate void D(Invoke x); @@ -3625,19 +3625,16 @@ private void AddSynthesizedExtensionImplementationsIfNecessary(MembersAndInitial private void AddSynthesizedExtensionMarker(MembersAndInitializersBuilder builder, DeclaredMembersAndInitializers declaredMembersAndInitializers) { - var syntax = (ExtensionDeclarationSyntax)this.GetNonNullSyntaxNode(); - var parameterList = syntax.ParameterList; - Debug.Assert(parameterList is not null); - - if (parameterList is null) + var marker = CreateSynthesizedExtensionMarker(); + if (marker is not null) { - return; + builder.AddNonTypeMember(this, marker, declaredMembersAndInitializers); } + } - int count = parameterList.Parameters.Count; - Debug.Assert(count > 0); - - builder.AddNonTypeMember(this, new SynthesizedExtensionMarker(this, parameterList), declaredMembersAndInitializers); + protected virtual MethodSymbol? CreateSynthesizedExtensionMarker() + { + throw ExceptionUtilities.Unreachable(); } private void AddDeclaredNontypeMembers(DeclaredMembersAndInitializersBuilder builder, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Extension.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Extension.cs index 665c475429e04..11180ec9376f7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Extension.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Extension.cs @@ -5,9 +5,11 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -19,7 +21,8 @@ internal partial class SourceNamedTypeSymbol private class ExtensionInfo { - public StrongBox? LazyExtensionParameter; + public MethodSymbol? LazyExtensionMarker = ErrorMethodSymbol.UnknownMethod; + public ParameterSymbol? LazyExtensionParameter; public ImmutableDictionary? LazyImplementationMap; } @@ -56,30 +59,14 @@ internal sealed override ParameterSymbol? ExtensionParameter return null; } - if (_lazyExtensionInfo is null) - { - Interlocked.CompareExchange(ref _lazyExtensionInfo, new ExtensionInfo(), null); - } + var markerMethod = TryGetOrCreateExtensionMarker(); - if (_lazyExtensionInfo.LazyExtensionParameter == null) + if (_lazyExtensionInfo.LazyExtensionParameter == null && markerMethod is { Parameters: [var parameter, ..] }) { - var extensionParameter = makeExtensionParameter(this); - Interlocked.CompareExchange(ref _lazyExtensionInfo.LazyExtensionParameter, new StrongBox(extensionParameter), null); + Interlocked.CompareExchange(ref _lazyExtensionInfo.LazyExtensionParameter, new ReceiverParameterSymbol(this, parameter), null); } - return _lazyExtensionInfo.LazyExtensionParameter.Value; - - static ParameterSymbol? makeExtensionParameter(SourceNamedTypeSymbol symbol) - { - var markerMethod = symbol.GetMembers(WellKnownMemberNames.ExtensionMarkerMethodName).OfType().SingleOrDefault(); - - if (markerMethod is not { Parameters: [var parameter, ..] }) - { - return null; - } - - return new ReceiverParameterSymbol(symbol, parameter); - } + return _lazyExtensionInfo.LazyExtensionParameter; } } @@ -115,6 +102,46 @@ internal sealed override ParameterSymbol? ExtensionParameter return _lazyExtensionInfo.LazyImplementationMap.GetValueOrDefault(method); } + protected sealed override MethodSymbol? CreateSynthesizedExtensionMarker() + { + return TryGetOrCreateExtensionMarker(); + } + + [MemberNotNull(nameof(_lazyExtensionInfo))] + private MethodSymbol? TryGetOrCreateExtensionMarker() + { + Debug.Assert(IsExtension); + + if (_lazyExtensionInfo is null) + { + Interlocked.CompareExchange(ref _lazyExtensionInfo, new ExtensionInfo(), null); + } + + if (_lazyExtensionInfo.LazyExtensionMarker == (object)ErrorMethodSymbol.UnknownMethod) + { + Interlocked.CompareExchange(ref _lazyExtensionInfo.LazyExtensionMarker, tryCreateExtensionMarker(), ErrorMethodSymbol.UnknownMethod); + } + + return _lazyExtensionInfo.LazyExtensionMarker; + + MethodSymbol? tryCreateExtensionMarker() + { + var syntax = (ExtensionDeclarationSyntax)this.GetNonNullSyntaxNode(); + var parameterList = syntax.ParameterList; + Debug.Assert(parameterList is not null); + + if (parameterList is null) + { + return null; + } + + int count = parameterList.Parameters.Count; + Debug.Assert(count > 0); + + return new SynthesizedExtensionMarker(this, parameterList); + } + } + internal static Symbol? GetCompatibleSubstitutedMember(CSharpCompilation compilation, Symbol extensionMember, TypeSymbol receiverType) { Debug.Assert(extensionMember.GetIsNewExtensionMember()); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index 7ef16c98c7b96..f8fe6efbb6a3d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -1141,24 +1141,37 @@ private ImmutableArray MakeTypeParameters(MethodDeclaration // Note: It is not an error to have a type parameter named the same as its enclosing method: void M() {} - for (int i = 0; i < result.Count; i++) + var tpEnclosing = ContainingType.FindEnclosingTypeParameter(name); + bool checkForDuplicates = true; + + if ((object)tpEnclosing != null) { - if (name == result[i].Name) + if (tpEnclosing.ContainingSymbol is NamedTypeSymbol { IsExtension: true }) + { + diagnostics.Add(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, location, name); + checkForDuplicates = false; + } + else { - diagnostics.Add(ErrorCode.ERR_DuplicateTypeParameter, location, name); - break; + // Type parameter '{0}' has the same name as the type parameter from outer type '{1}' + diagnostics.Add(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, location, name, tpEnclosing.ContainingType); } } - SourceMemberContainerTypeSymbol.ReportReservedTypeName(identifier.Text, this.DeclaringCompilation, diagnostics.DiagnosticBag, location); - - var tpEnclosing = ContainingType.FindEnclosingTypeParameter(name); - if ((object)tpEnclosing != null) + if (checkForDuplicates) { - // Type parameter '{0}' has the same name as the type parameter from outer type '{1}' - diagnostics.Add(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, location, name, tpEnclosing.ContainingType); + for (int i = 0; i < result.Count; i++) + { + if (name == result[i].Name) + { + diagnostics.Add(ErrorCode.ERR_DuplicateTypeParameter, location, name); + break; + } + } } + SourceMemberContainerTypeSymbol.ReportReservedTypeName(identifier.Text, this.DeclaringCompilation, diagnostics.DiagnosticBag, location); + var syntaxRefs = ImmutableArray.Create(parameter.GetReference()); var locations = ImmutableArray.Create(location); var typeParameter = (typeMap != null) ? diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index b7d5c4b4d4742..b5cd129376f0b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -683,6 +683,19 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, } } + if (SetMethod is { } setter && this.GetIsNewExtensionMember()) + { + if (ContainingType.TypeParameters.Any(static tp => tp.Name == ParameterSymbol.ValueParameterName)) + { + diagnostics.Add(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, setter.GetFirstLocationOrNone()); + } + + if (ContainingType.ExtensionParameter is { Name: ParameterSymbol.ValueParameterName }) + { + diagnostics.Add(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, setter.GetFirstLocationOrNone()); + } + } + if (!IsStatic && this.GetIsNewExtensionMember() && ContainingType.ExtensionParameter is { } extensionParameter && !this.IsNoMoreVisibleThan(extensionParameter.Type, ref useSiteInfo)) { diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 320131a89b1ad..9c31d578b65cc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1716,22 +1716,21 @@ internal static void GetAllTypeParameters(this NamedTypeSymbol type, ArrayBuilde /// internal static TypeParameterSymbol? FindEnclosingTypeParameter(this NamedTypeSymbol type, string name) { - var allTypeParameters = ArrayBuilder.GetInstance(); - type.GetAllTypeParameters(allTypeParameters); - - TypeParameterSymbol? result = null; - - foreach (TypeParameterSymbol tpEnclosing in allTypeParameters) + do { - if (name == tpEnclosing.Name) + foreach (TypeParameterSymbol tpEnclosing in type.TypeParameters) { - result = tpEnclosing; - break; + if (name == tpEnclosing.Name) + { + return tpEnclosing; + } } + + type = type.ContainingType; } + while (type is not null); - allTypeParameters.Free(); - return result; + return null; } /// diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 9459f9c618a4c..b09597a159c5b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1272,6 +1272,11 @@ Argument diagnosticId atributu Experimental musí být platný identifikátor + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. {0} není platný modifikátor návratového typu ukazatele na funkci. Platné modifikátory jsou ref a ref readonly. @@ -1412,6 +1417,16 @@ Vzory seznamů nelze použít pro hodnotu typu {0}. Nenašla se žádná vhodná vlastnost Length nebo Count. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Žádná přetížená metoda {0} neodpovídá ukazateli na funkci {1}. @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Primární konstruktor je v konfliktu se syntetizovaně zkopírovaným konstruktorem. @@ -2317,6 +2337,16 @@ Aby se typ {0} dal použít jako konvence volání, musí být veřejný. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Před vrácením řízení volajícímu se musí plně přiřadit automaticky implementovaná vlastnost {0}. Zvažte aktualizaci jazykové verze {1} na automatické výchozí nastavení vlastnosti. @@ -2417,6 +2447,16 @@ Objekt this nelze použít před přiřazením všech jeho polí. Zvažte aktualizaci na jazykovou verzi {0} na automatické výchozí nastavení nepřiřazených polí. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 176d7ae3a3c36..469cd4e7bc21a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1272,6 +1272,11 @@ Das diagnosticId-Argument für das Experimental-Attribut muss ein gültiger Bezeichner sein. + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. "{0}" ist kein gültiger Rückgabetyp-Modifizierer für Funktionszeiger. Gültige Modifizierer sind "ref" und "ref readonly". @@ -1412,6 +1417,16 @@ Listenmuster dürfen nicht für einen Wert vom Typ „{0}“ verwendet werden. Es wurde keine geeignete Längen- oder Anzahl-Eigenschaft gefunden. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Keine Überladung für "{0}" stimmt mit dem Funktionszeiger "{1}" überein. @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Der primäre Konstruktor verursacht einen Konflikt mit dem synthetisierten Kopierkonstruktor. @@ -2317,6 +2337,16 @@ Der Typ "{0}" muss öffentlich sein, damit er als Aufrufkonvention verwendet werden kann. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Die automatisch implementierte Eigenschaft '{0}' muss vollständig zugewiesen werden, bevor das Steuerelement an den Aufrufer zurückgegeben wird. Erwägen Sie eine Aktualisierung auf die Sprachversion '{1}', um die Eigenschaft automatisch als Standard zu verwenden. @@ -2417,6 +2447,16 @@ Das „this“-Objekt kann nicht verwendet werden, bevor alle zugehörigen Felder zugewiesen wurden. Aktualisieren Sie ggf. auf die Sprachversion „{0}“, um die nicht zugewiesenen Felder automatisch als Standard zu verwenden. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 45d718895d613..5343297526990 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1272,6 +1272,11 @@ El argumento diagnosticId del atributo "Experimental" debe ser un identificador válido. + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. "{0}" no es un modificador de tipo de valor devuelto de puntero de función válido. Los modificadores válidos son "ref" y "ref readonly". @@ -1412,6 +1417,16 @@ No se pueden usar patrones de lista para un valor de tipo \"{0}\". No se encontró ninguna propiedad \"Length\" o \"Count\" adecuada. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Ninguna sobrecarga correspondiente a "{0}" coincide con el puntero de función "{1}". @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. El constructor principal está en conflicto con el constructor de copia sintetizado. @@ -2317,6 +2337,16 @@ El tipo "{0}" debe ser público para poder usarlo como convención de llamada. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. La propiedad implementada automáticamente '{0}' debe estar totalmente asignada antes de que el control se devuelva al autor de la llamada. Considere la posibilidad de actualizar a la versión de idioma "{1}" para establecer automáticamente el valor predeterminado de la propiedad. @@ -2417,6 +2447,16 @@ No se puede usar el objeto 'this' antes de que se hayan asignado todos sus campos. Considere la posibilidad de actualizar a la versión de idioma "{0}" para establecer automáticamente el valor predeterminado de los campos sin asignar. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 7b3ca03bb3053..e743998dfb416 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1272,6 +1272,11 @@ L’argument diagnosticId de l’attribut « Experimental » doit être un identificateur valide + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' n'est pas un modificateur de type de retour de pointeur de fonction valide. Les modificateurs valides sont 'ref' et 'ref readonly'. @@ -1412,6 +1417,16 @@ Les modèles de liste ne peuvent pas être utilisés pour une valeur de type '{0}'. Aucune propriété 'Longueur' ou 'Compte' appropriée n’a été trouvée. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Aucune surcharge pour '{0}' ne correspond au pointeur de fonction '{1}' @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Le constructeur principal est en conflit avec le constructeur de copie synthétisée. @@ -2317,6 +2337,16 @@ Le type '{0}' doit être public pour être utilisé comme convention d'appel. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. La propriété implémentée automatiquement '{0}' doit être entièrement affectée avant que le contrôle soit retourné à l’appelant. Envisagez de mettre à jour la version de langue «{1}» pour définir automatiquement la propriété par défaut. @@ -2417,6 +2447,16 @@ Impossible d’utiliser l’objet 'this' avant l’affectation de tous ses champs. Envisagez de mettre à jour vers la version de langage '{0}' pour définir automatiquement les champs non attribués par défaut. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 2130f8b9ad2af..23a40c59d4606 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1272,6 +1272,11 @@ L'argomento diagnosticId dell'attributo 'Experimental' deve essere un identificatore valido + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' non è un modificatore di tipo restituito di puntatore a funzione valido. I modificatori validi sono 'ref' e 'ref readonly'. @@ -1412,6 +1417,16 @@ I criteri di elenco non possono essere utilizzati per un valore di tipo '{0}'. Non è stata trovata alcuna proprietà 'Length' o 'Count' appropriata. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Nessun overload per '{0}' corrisponde al puntatore a funzione '{1}' @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Il costruttore primario è in conflitto con il costruttore di copia sintetizzato. @@ -2317,6 +2337,16 @@ Il tipo '{0}' deve essere pubblico per poterlo usare come convenzione di chiamata. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. La proprietà implementata automaticamente '{0}' deve essere assegnata completamente prima che il controllo sia restituito al chiamante. Provare a eseguire l'aggiornamento alla versione del linguaggio '{1}' per impostare automaticamente la proprietà come predefinita. @@ -2417,6 +2447,16 @@ Impossibile utilizzare l'oggetto 'this' prima dell'assegnazione di tutti i relativi campi. Provare a eseguire l'aggiornamento alla versione del linguaggio '{0}' per impostare come predefiniti automaticamente i campi non assegnati. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 72f07dc060d5a..88947ad5ba5bc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1272,6 +1272,11 @@ 'Experimental' 属性への diagnosticId 引数は有効な識別子である必要があります + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' は有効な関数ポインターの戻り値の型修飾子ではありません。有効な修飾子は 'ref ' および 'ref readonly' です。 @@ -1412,6 +1417,16 @@ リスト パターンは、型 '{0}' の値には使用できません。適切な 'Length' または 'Count' プロパティが見つかりませんでした。 + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' 関数ポインター '{1}' に一致する '{0}' のオーバーロードはありません @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. プライマリ コンストラクターが、合成されたコピー コンストラクターと競合しています。 @@ -2317,6 +2337,16 @@ 呼び出し規則として使用する型 '{0}' はパブリックでなければなりません。 + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. コントロールを呼び出し元に返す前に、自動実装プロパティ '{0}' を完全に割り当てる必要があります。プロパティを自動既定値にするため '{1}' 言語バージョンに更新することを検討してください。 @@ -2417,6 +2447,16 @@ すべてのフィールドが割り当てられる前に、'this' オブジェクトを使用することはできません。割り当てられていないフィールドを自動既定値にするため '{0}' 言語バージョンに更新することを検討してください。 + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 4a3817f66a103..38f1f22255213 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1272,6 +1272,11 @@ 'Experimental' 특성에 대한 diagnosticId 인수는 유효한 식별자여야 합니다. + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}'은(는) 유효한 함수 포인터 반환 형식 한정자가 아닙니다. 유효한 한정자는 'ref' 및 'ref readonly'입니다. @@ -1412,6 +1417,16 @@ 목록 패턴은 '{0}' 형식의 값에 사용할 수 없습니다. 적합한 'Length' 또는 'Count' 속성을 찾을 수 없습니다. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' 함수 포인터 '{1}'과(와) 일치하는 '{0}'에 대한 오버로드가 없습니다. @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. 기본 생성자가 합성된 복사 생성자와 충돌합니다. @@ -2317,6 +2337,16 @@ 호출 규칙으로 사용하려면 '{0}' 형식이 public이어야 합니다. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. 제어가 호출자에게 반환되기 전에 자동 구현 속성 '{0}'이(가) 완전히 할당되어야 합니다. 속성을 자동으로 기본 설정하려면 언어 버전 '{1}'(으)로 업데이트하는 것이 좋습니다. @@ -2417,6 +2447,16 @@ 모든 필드가 할당되기 전에는 'this' 개체를 사용할 수 없습니다. 할당되지 않은 필드의 기본값을 자동으로 설정하려면 언어 버전 '{0}'(으)로 업데이트하는 것이 좋습니다. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 536c7fc18c346..66b7b56a43a3e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1272,6 +1272,11 @@ Argument diagnosticId atrybutu „Experimental” musi być prawidłowym identyfikatorem + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. Element „{0}” nie jest prawidłowym modyfikatorem zwracanego typu wskaźnikowego funkcji. Prawidłowe modyfikatory to „ref” i „ref readonly”. @@ -1412,6 +1417,16 @@ Wzorce listy nie mogą być używane dla wartości typu „{0}”. Nie znaleziono odpowiedniej właściwości „Długość” ani „Liczba”. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Żadne z przeciążeń dla elementu „{0}” nie pasuje do wskaźnika funkcji „{1}” @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Konstruktor podstawowy powoduje konflikt z konstruktorem syntetyzowanej kopii. @@ -2317,6 +2337,16 @@ Typ „{0}” musi być publiczny, aby można go było używać jako konwencji wywoływania. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Automatycznie implementowana właściwość „{0}” musi być w pełni przypisana, zanim kontrolka zostanie zwrócona do obiektu wywołującego. Rozważ zaktualizowanie do wersji językowej „{1}”, aby automatycznie ustawić domyślną właściwość. @@ -2417,6 +2447,16 @@ Nie można użyć obiektu „this” przed przypisaniem wszystkich jego pól. Rozważ zaktualizowanie nieprzypisanych pól do wersji językowej „{0}”, aby automatycznie ustawić domyślne pola niezaznaczone. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 583a9fab0ce36..b81dd3ed263ff 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1272,6 +1272,11 @@ O argumento diagnosticId para o atributo 'Experimental' deve ser um identificador válido + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}' não é um modificador de tipo de retorno de ponteiro de função válido. Os modificadores válidos são 'ref' e 'ref readonly'. @@ -1412,6 +1417,16 @@ Padrões de lista não podem ser usados para um valor do tipo “{0}”. Nenhuma propriedade “Length” ou “Count” adequada foi encontrada. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Nenhuma sobrecarga de '{0}' corresponde ao ponteiro de função '{1}' @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. O construtor primário entra em conflito com o construtor de cópia sintetizado. @@ -2317,6 +2337,16 @@ O tipo '{0}' precisa ser público para ser usado como uma convenção de chamada. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. A propriedade auto-implementada '{0}' deve ser totalmente atribuída antes que o controle seja devolvido ao chamador. Considere atualizar para a versão de linguagem '{1}' para auto-padrão da propriedade. @@ -2417,6 +2447,16 @@ O objeto 'this' não pode ser usado antes que todos os seus campos serem atribuídos. Considere atualizar para a versão de linguagem '{0}' para auto-padrão dos campos não atribuídos. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 22a64d9ff9f57..54b5bb421dd11 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1272,6 +1272,11 @@ Аргумент diagnosticId атрибута "Experimental" должен быть допустимым идентификатором + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. "{0}" не является допустимым модификатором типа для возвращаемого значения указателя на функцию. Допустимые модификаторы: ref и ref readonly. @@ -1412,6 +1417,16 @@ Шаблоны списка не могут использоваться для значения типа {0}. Подходящее свойство \"Length\" или \"Count\" не найдено. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' Нет перегруженного метода для "{0}", который соответствует указателю на функцию "{1}". @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Первичный конструктор конфликтует с синтезированным конструктором копий. @@ -2317,6 +2337,16 @@ Тип "{0}" должен быть открытым для использования в качестве соглашения о вызовах. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Автоматически реализуемое свойство "{0}" должно быть полностью назначено перед возвратом контроля вызывающему элементу. Попробуйте обновить до языковой версии "{1}", чтобы автоматически применить значение по умолчанию к этому свойству. @@ -2417,6 +2447,16 @@ Нельзя использовать объект "this", пока не будут назначены все его поля. Попробуйте обновить до языковой версии "{0}", чтобы автоматически применить значения по умолчанию к неназначенным полям. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index e94e6548f4d95..0dae5a8b1a1ae 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1272,6 +1272,11 @@ 'Experimental' özniteliğinin diagnosticId bağımsız değişkeni geçerli bir tanımlayıcı olmalıdır + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}', geçerli bir işlev işaretçisi dönüş türü değiştiricisi değil. Geçerli değiştiriciler: 'ref' ve 'ref readonly'. @@ -1412,6 +1417,16 @@ Liste desenleri, '{0}' türündeki bir değer için kullanılamaz. Uygun 'Length' veya 'Count' özelliği bulunamadı. + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' '{0}' için aşırı yüklemelerin hiçbiri '{1}' işlev işaretçisiyle eşleşmiyor @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. Birincil oluşturucu, sentezlenmiş kopya oluşturucusuyla çakışıyor. @@ -2317,6 +2337,16 @@ '{0}' türünün bir çağırma kuralı olarak kullanılabilmesi için genel olması gerekir. + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Denetim çağırana döndürülmeden önce otomatik uygulanan '{0}' özelliği tam olarak atanmalıdır. Özelliği otomatik olarak varsayılan durumuna getirmek için '{1}' dil sürümüne güncelleştirmeyi düşünün. @@ -2417,6 +2447,16 @@ 'this' nesnesi, tüm alanları atanmadan önce kullanılamaz. Atanmamış alanları otomatik olarak varsayılan durumuna getirmek için '{0}' dil sürümüne güncelleştirmeyi düşünün. + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 5221253ba2740..b821f47ecd29e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1272,6 +1272,11 @@ “Experimental” 属性的 diagnosticId 参数必须是有效的标识符 + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. “{0}”不是有效的函数指针返回类型修饰符。有效的修饰符为 "ref" 和 "ref readonly"。 @@ -1412,6 +1417,16 @@ 列表模式不能用于 '{0}' 类型的值。找不到合适的 \"Length\" 或 \"Count\" 属性。 + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' “{0}”没有与函数指针“{1}”匹配的重载 @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. 主构造函数与合成的复制构造函数冲突。 @@ -2317,6 +2337,16 @@ 类型“{0}”必须是公共的,才能用作调用约定。 + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. 必须先完全分配自动实现的属性'{0}',然后才能将控件返回到调用方。请考虑更新到语言版本'{1}'以自动默认属性。 @@ -2417,6 +2447,16 @@ 在分配“this”对象的所有字段之前,无法使用该对象。请考虑更新到语言版本 '{0}' 以自动默认未分配的字段。 + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index b14ab56ed66c4..781a4090f677e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1272,6 +1272,11 @@ 'Experimental' 屬性的 diagnosticId 引數必須是有效的識別碼 + + Cannot use extension parameter '{0}' in this context. + Cannot use extension parameter '{0}' in this context. + + '{0}' is not a valid function pointer return type modifier. Valid modifiers are 'ref' and 'ref readonly'. '{0}'不是有效的函式指標傳回型別修飾元。有效的修飾元為 'ref' 與 'ref readonly'。 @@ -1412,6 +1417,16 @@ 清單模式不能用於型別 '{0}' 的值。找不到適當的 'Length' 或 'Count' 屬性。 + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension parameter + + + + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + '{0}': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + + No overload for '{0}' matches function pointer '{1}' '{0}' 沒有任何多載符合函式指標 '{1}' @@ -1907,6 +1922,11 @@ An extension container can have only one receiver parameter + + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + '{0}': a receiver parameter cannot have the same name as an extension container type parameter + + The primary constructor conflicts with the synthesized copy constructor. 主要建構函式與合成的複製建構函式相衝突。 @@ -2317,6 +2337,16 @@ 類型 '{0}' 必須是公用,才能用為呼叫慣例。 + + Type parameter '{0}' has the same name as an extension parameter + Type parameter '{0}' has the same name as an extension parameter + + + + Type parameter '{0}' has the same name as an extension container type parameter + Type parameter '{0}' has the same name as an extension container type parameter + + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. 在控制項傳回呼叫者之前,必須先完全指派自動實作屬性 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設屬性。 @@ -2417,6 +2447,16 @@ 在指派 'this' 物件的所有欄位之前,無法使用該物件。請考慮更新語言版本 '{0}',以自動預設未指派的欄位。 + + 'value': an automatically-generated parameter name conflicts with an extension parameter name + 'value': an automatically-generated parameter name conflicts with an extension parameter name + + + + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + 'value': an automatically-generated parameter name conflicts with an extension type parameter name + + In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. In language version {0}, 'field' is a keyword within a property accessor. Rename the variable or use the identifier '@field' instead. diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs index cb681b90009bd..73e783a5e9fcf 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -504,10 +504,7 @@ void T() { } } """; var comp = CreateCompilation(src); - comp.VerifyEmitDiagnostics( - // (5,14): error CS0102: The type 'Extensions.extension(object)' already contains a definition for 'T' - // void T() { } - Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "T").WithArguments("Extensions.extension(object)", "T").WithLocation(5, 14)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -1275,9 +1272,13 @@ void M2(int T) { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( - // (5,16): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(object)' + // (5,16): error CS9508: Type parameter 'T' has the same name as an extension container type parameter // void M() { } - Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(object)").WithLocation(5, 16)); + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(5, 16), + // (6,21): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // void M2(int T) { } + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(6, 21) + ); } [Fact] @@ -2010,12 +2011,13 @@ public MyAttribute(string s) { } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( - // (3,16): error CS0103: The name 'o' does not exist in the current context + // (3,6): error CS0592: Attribute 'My' is not valid on this declaration type. It is only valid on 'assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter' declarations. // [My(nameof(o)), My(nameof(Extensions))] - Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(3, 16), - // (3,21): error CS0592: Attribute 'My' is not valid on this declaration type. It is only valid on 'assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter' declarations. + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "My").WithArguments("My", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(3, 6), + // (3,21): error CS0579: Duplicate 'My' attribute // [My(nameof(o)), My(nameof(Extensions))] - Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "My").WithArguments("My", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(3, 21)); + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "My").WithArguments("My").WithLocation(3, 21) + ); } [Fact] @@ -3303,9 +3305,9 @@ private void M2(C c) {} extension(long x) { - public static void M3(int x) + public static void M3(int y) { - x.M2(new C()); + y.M2(new C()); } } @@ -3340,9 +3342,9 @@ public static class Extensions extension(long x) { - public static void M3(int x) + public static void M3(int y) { - _ = x.M2; + _ = y.M2; } } @@ -3470,8 +3472,8 @@ file static class Extensions { public void M1(C c) {} public C P => null; - public C this[int x] => null; - public int this[C x] => 0; + public C this[int y] => null; + public int this[C y] => 0; } public static void M2(this int x, C c) {} @@ -3630,7 +3632,7 @@ public int M() } [Fact] - public void ReceiverNotInScopeInStaticMember() + public void ReceiverInScopeButIllegalInStaticMember() { var src = """ public static class Extensions @@ -3646,18 +3648,18 @@ public static class Extensions """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( - // (5,31): error CS0103: The name 'o' does not exist in the current context + // (5,31): error CS9512: Cannot use extension parameter 'object o' in this context. // static object M1() => o; - Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(5, 31), - // (6,37): error CS0103: The name 'o' does not exist in the current context + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(5, 31), + // (6,37): error CS9512: Cannot use extension parameter 'object o' in this context. // static object M2() { return o; } - Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(6, 37), - // (7,29): error CS0103: The name 'o' does not exist in the current context + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(6, 37), + // (7,29): error CS9512: Cannot use extension parameter 'object o' in this context. // static object P1 => o; - Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(7, 29), - // (8,41): error CS0103: The name 'o' does not exist in the current context + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(7, 29), + // (8,41): error CS9512: Cannot use extension parameter 'object o' in this context. // static object P2 { get { return o; } } - Diagnostic(ErrorCode.ERR_NameNotInContext, "o").WithArguments("o").WithLocation(8, 41) + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "o").WithArguments("object o").WithLocation(8, 41) ); } @@ -6924,9 +6926,9 @@ static class Extensions { extension(object o) { - public static string M2(object o, string s) + public static string M2(object o1, string s) { - return object.M(o, s); + return object.M(o1, s); } } } @@ -7013,9 +7015,9 @@ static class Extensions_ { extension(object o) { - public static string M2(object o, string s) + public static string M2(object o1, string s) { - return Extensions.M(o, s); + return Extensions.M(o1, s); } } } @@ -7070,9 +7072,9 @@ static class Extensions { extension(object o) { - public static string M2(object o, string s) + public static string M2(object o1, string s) { - return new System.Func(object.M)(o, s); + return new System.Func(object.M)(o1, s); } } } @@ -7154,9 +7156,9 @@ static class Extensions_ { extension(object o) { - public static string M2(object o, string s) + public static string M2(object o1, string s) { - return new System.Func(Extensions.M)(o, s); + return new System.Func(Extensions.M)(o1, s); } } } @@ -7194,9 +7196,9 @@ static class Extensions { extension(object o) { - unsafe public static string M2(object o, string s) + unsafe public static string M2(object o1, string s) { - return ((delegate*)&object.M)(o, s); + return ((delegate*)&object.M)(o1, s); } } } @@ -7274,9 +7276,9 @@ static class Extensions_ { extension(object o) { - unsafe public static string M2(object o, string s) + unsafe public static string M2(object o1, string s) { - return ((delegate*)&Extensions.M)(o, s); + return ((delegate*)&Extensions.M)(o1, s); } } } @@ -11466,7 +11468,7 @@ static class E { extension(object o) { - public void M(object o) => throw null; + public void M(object o1) => throw null; } public static void M2(this object o, object o2) => throw null; } @@ -11483,7 +11485,7 @@ static class E var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new object().M"); - Assert.Equal(["void E.<>E__0.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal(["void E.<>E__0.M(System.Object o1)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] @@ -12113,7 +12115,7 @@ static class E1 extension(C c) { public void M(string s) => throw null; - public void M(char c) => throw null; + public void M(char c1) => throw null; } } @@ -12130,7 +12132,7 @@ static class E2 var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new C().M"); Assert.Equal("void C.M(System.Int32 i)", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()", "void E1.<>E__0.M(System.String s)", "void E1.<>E__0.M(System.Char c)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + Assert.Equal(["void C.M()", "void E1.<>E__0.M(System.String s)", "void E1.<>E__0.M(System.Char c1)", "void C.M(System.Int32 i)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact] @@ -21304,6 +21306,1578 @@ static class E Assert.Equal("extension(ref readonly Int32)", symbol.ToDisplayString(format)); } + [Fact] + public void NameConflict_01_EnclosingStaticTypeNameWithExtensionTypeParameterName() + { + var src = """ +static class Extensions +{ + extension(int) + { + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_02_EnclosingStaticTypeNameWithReceiverParameterName() + { + var src = """ +static class Extensions +{ + extension(int Extensions) + { + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_03_ExtensionTypeParameterNameWithReceiverParameterName() + { + var src = """ +static class Extensions +{ +#line 7 + extension(T[] T) + { + void M1(){} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (7,22): error CS9506: 'T': a receiver parameter cannot have the same name as an extension container type parameter + // extension(T[] T) + Diagnostic(ErrorCode.ERR_ReceiverParameterSameNameAsTypeParameter, "T").WithArguments("T").WithLocation(7, 22) + ); + } + + [Fact] + public void NameConflict_04_ExtensionTypeParameterNameWithMemberParameterName() + { + var src = """ +static class Extensions +{ + extension(T[] p) + { +#line 14 + void M2(int T){} + static void M3(int T){} + int this[int T] => 0; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (14,21): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // void M2(int T){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(14, 21), + // (15,28): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // static void M3(int T){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(15, 28), + // (16,22): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int this[int T] => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(16, 22) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_05_ExtensionTypeParameterNameWithSetterValueParameter(bool isStatic) + { + var src = @" +static class Extensions +{ + extension(value[] p) + { + " + (isStatic ? "static" : "") + @" + int P11 {set{}} + + " + (isStatic ? "static" : "") + @" + int P12 => 0; + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (4,15): warning CS8981: The type name 'value' only contains lower-cased ascii characters. Such names may become reserved for the language. + // extension(value[] p) + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "value").WithArguments("value").WithLocation(4, 15), + // (7,18): error CS9513: 'value': an automatically-generated parameter name conflicts with an extension type parameter name + // int P11 {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, "set").WithLocation(7, 18) + ); + } + + [Fact] + public void NameConflict_06_ExtensionTypeParameterNameWithSetterValueParameter() + { + var src = @" +static class Extensions +{ + extension(value[] p) + { + int this[int i] {set{}} + int this[long i] => 0; + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (4,15): warning CS8981: The type name 'value' only contains lower-cased ascii characters. Such names may become reserved for the language. + // extension(value[] p) + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "value").WithArguments("value").WithLocation(4, 15), + // (6,26): error CS9513: 'value': an automatically-generated parameter name conflicts with an extension type parameter name + // int this[int i] {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter, "set").WithLocation(6, 26) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_07_ExtensionTypeParameterNameWithLocalFunctionParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local(int T) + { + return T; + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local(int T) + { + return T; + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_08_ExtensionTypeParameterNameWithLambdaParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"(int T) => + { + return T; + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"(int T) => + { + return T; + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_09_ExtensionTypeParameterNameWithLocalName(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier + @"int M4() + { +#line 19 + int T = 0; + return T; + } + " + modifier + @"int M5() + { + int T() => 0; + return T(); + } + " + modifier + @"int P7 + { + get + { + int T = 0; + return T; + } + } + " + modifier + @"int P8 + { + get + { + int T() => 0; + return T(); + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (19,17): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T = 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(19, 17), + // (24,17): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T() => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(24, 17), + // (31,21): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T = 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(31, 21), + // (39,21): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // int T() => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(39, 21) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_10_ExtensionTypeParameterNameWithLocalNameInLocalFunction(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local() + { + int T = 0; + return T; + } + } + " + modifier1 + @"void M5() + { + " + modifier2 + @"int local() + { + int T() => 0; + return T(); + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local() + { + int T = 0; + return T; + } + } + } + " + modifier1 + @"int P8 + { + set + { + " + modifier2 + @"int local() + { + int T() => 0; + return T(); + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_11_ExtensionTypeParameterNameWithLocalNameInLambda(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"() => + { + int T = 0; + return T; + }; + } + " + modifier1 + @"void M5() + { + System.Func l = " + modifier2 + @"() => + { + int T() => 0; + return T(); + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int T = 0; + return T; + }; + } + } + " + modifier1 + @"int P8 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int T() => 0; + return T(); + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_12_ExtensionTypeParameterNameWithAnotherExtensionTypeParameterName() + { + var src = """ +static class Extensions +{ +#line 55 + extension(T[] p) + {} +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (55,18): error CS0692: Duplicate type parameter 'T' + // extension(T[] p) + Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(55, 18), + // (55,21): error CS0229: Ambiguity between 'T' and 'T' + // extension(T[] p) + Diagnostic(ErrorCode.ERR_AmbigMember, "T").WithArguments("T", "T").WithLocation(55, 21) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_13_ExtensionTypeParameterNameWithMemberTypeParameterName(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(T[] p) + { + " + modifier + @" +#line 60 + void M9(){} + + " + modifier + @" +#line 61 + void M10(){} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (60,17): error CS9508: Type parameter 'T' has the same name as an extension container type parameter + // void M9(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(60, 17), + // (61,18): error CS9508: Type parameter 'T' has the same name as an extension container type parameter + // void M10(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(61, 18), + // (61,21): error CS9508: Type parameter 'T' has the same name as an extension container type parameter + // void M10(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(61, 21) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_14_ExtensionTypeParameterNameWithLocalFunctionTypeParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static" : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(T[] p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + " + modifier1 + @"void M5() + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P8 + { + set + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + // PROTOTYPE: We might need to add a new warning if we don't want to refer to extension as a type in diagnostics + + comp.VerifyEmitDiagnostics( + // (11,21): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(11, 21), + // (21,25): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(21, 25), + // (32,25): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(32, 25), + // (45,29): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Extensions.extension(T[])' + // T local(T p1) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Extensions.extension(T[])").WithLocation(45, 29) + ); + } + + [Fact] + public void NameConflict_15_ExtensionTypeParameterNameWithMemberName() + { + var src = """ +static class Extensions +{ + extension(C1 p) + { + int T() + { + return T; + } + } + + extension(C2 p) + { + int T => T; + } + + extension(C3 p) + { + [System.Runtime.CompilerServices.IndexerName("T")] + int this[int x] => T; + } + + extension(C4 p) + { + static int T() + { + return T; + } + } + + extension(C5 p) + { + static int T => T; + } +} + +class C1 {} +class C2 {} +class C3 {} +class C4 {} +class C5 {} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (7,20): error CS0119: 'T' is a type, which is not valid in the given context + // return T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(7, 20), + // (13,18): error CS0119: 'T' is a type, which is not valid in the given context + // int T => T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(13, 18), + // (19,28): error CS0119: 'T' is a type, which is not valid in the given context + // int this[int x] => T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(19, 28), + // (26,20): error CS0119: 'T' is a type, which is not valid in the given context + // return T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(26, 20), + // (32,25): error CS0119: 'T' is a type, which is not valid in the given context + // static int T => T; + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(32, 25) + ); + } + + [Fact] + public void NameConflict_16_ReceiverParameterNameWithMemberName() + { + var src = """ +static class Extensions +{ + extension(int M1) + { + void M1() + { + int x = M1; + x++; + } + } + + extension(long P1) + { + int P1 + { + get + { + P1 = long.MaxValue; + return 0; + } + } + } + + extension(byte Indexer) + { + [System.Runtime.CompilerServices.IndexerName("Indexer")] + int this[int y] + { + get + { + byte x = Indexer; + x++; + return 0; + } + } + } + + extension(short M1) + { + static void M1() + { + short x = M1; + x++; + } + } + + extension(string P1) + { + static int P1 + { + get + { + P1 = "val"; + return 0; + } + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (42,23): error CS9512: Cannot use extension parameter 'short M1' in this context. + // short x = M1; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "M1").WithArguments("short M1").WithLocation(42, 23), + // (53,17): error CS9512: Cannot use extension parameter 'string P1' in this context. + // P1 = "val"; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "P1").WithArguments("string P1").WithLocation(53, 17) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_17_ReceiverParameterNameWithMemberTypeParameterName(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(int T) + { + " + modifier + @" +#line 5 + void M1(){} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,17): error CS9511: Type parameter 'T' has the same name as an extension parameter + // void M1(){} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter, "T").WithArguments("T").WithLocation(5, 17) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_18_ReceiverParameterNameWithLocalFunctionTypeParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static" : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(int T) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + " + modifier1 + @"void M5() + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + " + modifier1 + @"int P8 + { + set + { + void local2() + { + " + modifier2 + @" + T local(T p1) + { + return p1; + } + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_19_ReceiverParameterNameWithMemberParameterName() + { + var src = """ +static class Extensions +{ + extension(int p) + { + void M2(int p){} + static void M3(int p){} + int this[int p] => 0; + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,21): error CS9509: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter + // void M2(int p){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(5, 21), + // (6,28): error CS9509: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter + // static void M3(int p){} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(6, 28), + // (7,22): error CS9509: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter + // int this[int p] => 0; + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(7, 22) + ); + } + + [Fact] + public void NameConflict_20_ReceiverParameterNameWithSetterValueParameter() + { + var src = """ +static class Extensions +{ + extension(int value) + { + int P1 {get=>0;} + int P2 {set{}} + int this[int x] {get=>0;} + int this[long x] {set{}} + int this[long x, int value] {set{}} + static int P6 {get=>0;} + static int P7 {set{}} + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,17): error CS9510: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // int P2 {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(6, 17), + // (8,27): error CS9510: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // int this[long x] {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(8, 27), + // (9,30): error CS9509: 'value': a parameter, local variable, or local function cannot have the same name as an extension parameter + // int this[long x, int value] {set{}} + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "value").WithArguments("value").WithLocation(9, 30), + // (9,30): error CS0316: The parameter name 'value' conflicts with an automatically-generated parameter name + // int this[long x, int value] {set{}} + Diagnostic(ErrorCode.ERR_DuplicateGeneratedName, "value").WithArguments("value").WithLocation(9, 30), + // (9,38): error CS9510: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // int this[long x, int value] {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(9, 38), + // (11,24): error CS9510: 'value': an automatically-generated parameter name conflicts with an extension parameter name + // static int P7 {set{}} + Diagnostic(ErrorCode.ERR_ValueParameterSameNameAsExtensionParameter, "set").WithLocation(11, 24) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_21_ReceiverParameterNameWithLocalFunctionParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local(int p) + { + return p; + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local(int p) + { + return p; + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_22_ReceiverParameterNameWithLambdaParameterName(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"(int p) => + { + return p; + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"(int p) => + { + return p; + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_23_ReceiverParameterNameWithLocalName(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + " + modifier + @"int M4() + { +#line 7 + int p = 0; + return p; + } + " + modifier + @"int M5() + { + int p() => 0; + return p(); + } + " + modifier + @"int P7 + { + get + { + int p = 0; + return p; + } + } + " + modifier + @"int P8 + { + get + { + int p() => 0; + return p(); + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (7,17): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p = 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(7, 17), + // (12,17): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p() => 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(12, 17), + // (19,21): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p = 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(19, 21), + // (27,21): error CS0136: A local or parameter named 'p' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // int p() => 0; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "p").WithArguments("p").WithLocation(27, 21) + ); + } + + [Theory] + [CombinatorialData] + public void NameConflict_24_ReceiverParameterNameWithLocalNameInLocalFunction(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +#pragma warning disable CS8321 // The local function 'local' is declared but never used + +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + " + modifier2 + @"int local() + { + int p = 0; + return p; + } + } + " + modifier1 + @"void M5() + { + " + modifier2 + @"int local() + { + int p() => 0; + return p(); + } + } + " + modifier1 + @"int P7 + { + set + { + " + modifier2 + @"int local() + { + int p = 0; + return p; + } + } + } + " + modifier1 + @"int P8 + { + set + { + " + modifier2 + @"int local() + { + int p() => 0; + return p(); + } + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NameConflict_25_ReceiverParameterNameWithLocalNameInLambda(bool isStatic1, bool isStatic2) + { + var modifier1 = isStatic1 ? "static " : ""; + var modifier2 = isStatic2 ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(string p) + { + " + modifier1 + @"void M4() + { + System.Func l = " + modifier2 + @"() => + { + int p = 0; + return p; + }; + } + " + modifier1 + @"void M5() + { + System.Func l = " + modifier2 + @"() => + { + int p() => 0; + return p(); + }; + } + " + modifier1 + @"int P7 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int p = 0; + return p; + }; + } + } + " + modifier1 + @"int P8 + { + set + { + System.Func l = " + modifier2 + @"() => + { + int p() => 0; + return p(); + }; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void NameConflict_26_ExampleFromSpec() + { + var src = @" +using System.Linq; + +public static class E +{ + extension(T[] ts) + { + public bool M1(T t) => ts.Contains(t); // `T` and `ts` are in scope + public static bool M2(T t) => ts.Contains(t); // Error: Cannot refer to `ts` from static context + public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` + public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (9,39): error CS9512: Cannot use extension parameter 'T[] ts' in this context. + // public static bool M2(T t) => ts.Contains(t); // Error: Cannot refer to `ts` from static context + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "ts").WithArguments("T[] ts").WithLocation(9, 39), + // (10,28): error CS9507: 'T': a parameter, local variable, or local function cannot have the same name as an extension container type parameter + // public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(10, 28), + // (10,38): error CS9509: 'ts': a parameter, local variable, or local function cannot have the same name as an extension parameter + // public void M3(int T, string ts) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "ts").WithArguments("ts").WithLocation(10, 38), + // (11,24): error CS9508: Type parameter 'T' has the same name as an extension container type parameter + // public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(11, 24), + // (11,27): warning CS8981: The type name 'ts' only contains lower-cased ascii characters. Such names may become reserved for the language. + // public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "ts").WithArguments("ts").WithLocation(11, 27), + // (11,27): error CS9511: Type parameter 'ts' has the same name as an extension parameter + // public void M4(string s) { } // Error: Cannot reuse names `T` and `ts` + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionParameter, "ts").WithArguments("ts").WithLocation(11, 27) + ); + } + + [Fact] + public void NameConflict_27_ExampleFromSpec() + { + var src = @" +public static class E +{ + extension(T[] ts) + { + public int T() { return M(ts); } // Generated static method M(T[]) is found + public string M() { return T(ts); } // Error: T is a type parameter + } +} + +class CTest +{ + static int M(T[] ts) + { + return T(ts); + } + + static int T(U[] ts) => 0; +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,33): error CS0029: Cannot implicitly convert type 'string' to 'int' + // public int T() { return M(ts); } // Generated static method M(T[]) is found + Diagnostic(ErrorCode.ERR_NoImplicitConv, "M(ts)").WithArguments("string", "int").WithLocation(6, 33), + // (7,36): error CS0119: 'T' is a type, which is not valid in the given context + // public string M() { return T(ts); } // Error: T is a type parameter + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(7, 36), + // (15,16): error CS0119: 'T' is a type, which is not valid in the given context + // return T(ts); + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(15, 16) + ); + } + + [Fact] + public void NameConflict_28_ExampleFromSpec() + { + var src = @" +public static class E +{ + extension(int P) + { + public int P() { return M(P); } // Generated static method M(T[]) is found + public string M() { return P(P); } // Error: P is a parameter + } +} + +class CTest +{ + static int M(int P) + { + return P(P); + } + + static int P(int P) => 0; +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,33): error CS0029: Cannot implicitly convert type 'string' to 'int' + // public int P() { return M(P); } // Generated static method M(T[]) is found + Diagnostic(ErrorCode.ERR_NoImplicitConv, "M(P)").WithArguments("string", "int").WithLocation(6, 33), + // (7,36): error CS0149: Method name expected + // public string M() { return P(P); } // Error: P is a parameter + Diagnostic(ErrorCode.ERR_MethodNameExpected, "P").WithLocation(7, 36), + // (15,16): error CS0149: Method name expected + // return P(P); + Diagnostic(ErrorCode.ERR_MethodNameExpected, "P").WithLocation(15, 16) + ); + } + + + [Fact] + public void NameConflict_29_WithStaticTypeTypeParameter() + { + var src = @" +public static class E +{ + extension(int p) + { + public void M1() {} + } + + extension(T[] p) + { + public void M2() {} + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (4,5): error CS9502: Extensions must be declared in a top-level, non-generic, static class + // extension(int p) + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(4, 5), + // (6,24): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'E' + // public void M1() {} + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "E").WithLocation(6, 24), + // (9,5): error CS9502: Extensions must be declared in a top-level, non-generic, static class + // extension(T[] p) + Diagnostic(ErrorCode.ERR_BadExtensionContainingType, "extension").WithLocation(9, 5), + // (9,15): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'E' + // extension(T[] p) + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "E").WithLocation(9, 15), + // (11,24): error CS9508: Type parameter 'T' has the same name as an extension container type parameter + // public void M2() {} + Diagnostic(ErrorCode.ERR_TypeParameterSameNameAsExtensionTypeParameter, "T").WithArguments("T").WithLocation(11, 24) + ); + } + + [Fact] + public void ReceiverParameterScope_01_InStaticMember() + { + var src = """ +static class Extensions +{ + extension(int p) + { + static int P1 { get => p; } + static int M2() + { + return p; + } + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (5,32): error CS9512: Cannot use extension parameter 'int p' in this context. + // static int P1 { get => p; } + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(5, 32), + // (8,20): error CS9512: Cannot use extension parameter 'int p' in this context. + // return p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(8, 20) + ); + } + + [Fact] + public void ReceiverParameterScope_02_InStaticMember() + { + var src = """ +static class Extensions +{ + extension(int p) + { + static int P1 + { + get + { + int local() => p; + return local(); + } + } + static int M2() + { + int local() => p; + return local(); + } + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (9,32): error CS9512: Cannot use extension parameter 'int p' in this context. + // int local() => p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(9, 32), + // (15,28): error CS9512: Cannot use extension parameter 'int p' in this context. + // int local() => p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(15, 28) + ); + } + + [Fact] + public void ReceiverParameterScope_03_InStaticMember() + { + var src = """ +static class Extensions +{ + extension(int p) + { + static string P1 { get => nameof(p); } + static string M2() + { + return nameof(p); + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameterScope_04_InStaticLocalFunction() + { + var src = """ +static class Extensions +{ + extension(int p) + { + int P1 + { + get + { + static int local() => p; + return local(); + } + } + int M2() + { + static int local() => p; + return local(); + } + } +} +"""; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (9,39): error CS8421: A static local function cannot contain a reference to 'p'. + // static int local() => p; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(9, 39), + // (15,35): error CS8421: A static local function cannot contain a reference to 'p'. + // static int local() => p; + Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(15, 35) + ); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_05_InAttribute(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + [MyAttr(nameof(p))] + " + modifier + @"int P1 { get => 0; } + + [MyAttr(nameof(p))] + " + modifier + @"int M2() + { + return 0; + } + } +} + +class MyAttr : System.Attribute +{ + public MyAttr(string s) {} +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_06_InAttribute(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + [MyAttr(p)] + " + modifier + @"int P1 { get => 0; } + + [MyAttr(p)] + " + modifier + @"int M2() + { + return 0; + } + } +} + +class MyAttr : System.Attribute +{ + public MyAttr(int p) {} +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (6,17): error CS9512: Cannot use extension parameter 'int p' in this context. + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(6, 17), + // (6,17): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(6, 17), + // (9,17): error CS9512: Cannot use extension parameter 'int p' in this context. + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(9, 17), + // (9,17): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [MyAttr(p)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(9, 17) + ); + } + + [Fact(Skip = "Cycle")] // PROTOTYPE: There is a cycle due to the attribute + public void ReceiverParameterScope_07_InAttribute() + { + var src = @" +static class Extensions +{ + extension(int p) + { + [System.Runtime.CompilerServices.IndexerName(nameof(p))] + int this[int y] + { + get + { + return 0; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void ReceiverParameterScope_08_InAttribute() + { + var src = @" +static class Extensions +{ + extension(string p) + { + [System.Runtime.CompilerServices.IndexerName(p)] + int this[int y] + { + get + { + return 0; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyDiagnostics( + // (6,54): error CS9512: Cannot use extension parameter 'string p' in this context. + // [System.Runtime.CompilerServices.IndexerName(p)] + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("string p").WithLocation(6, 54), + // (6,54): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [System.Runtime.CompilerServices.IndexerName(p)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(6, 54) + ); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_09_InDefaultValue(bool isStatic) + { + var modifier = isStatic ? "static " : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + " + modifier + @"int M2(string x = nameof(p)) + { + return 0; + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_10_InDefaultValue(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + " + modifier + @" +#line 6 + int M2(int x = p) + { + return 0; + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (6,24): error CS9512: Cannot use extension parameter 'int p' in this context. + // int M2(int x = p) + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(6, 24), + // (6,24): error CS1736: Default parameter value for 'x' must be a compile-time constant + // int M2(int x = p) + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "p").WithArguments("x").WithLocation(6, 24) + ); + } + + [Fact(Skip = "Cycle")] // PROTOTYPE: There is a cycle due to the attribute + public void CycleInAttribute_01() + { + var src = @" +static class Extensions +{ + static const string Str = ""val"" + extension(string p) + { + [System.Runtime.CompilerServices.IndexerName(Str)] + int this[int y] + { + get + { + return 0; + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics(); + } + [Fact] public void SignatureConflict_01() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs index 2d7ff0cb065f0..d03737a24fc77 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs @@ -7320,9 +7320,9 @@ public static void Main() // (27,27): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Derived1' // public class Derived2 : Outer>>.Inner>>.Interface> Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Derived1").WithLocation(27, 27), - // (37,28): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Derived1' + // (37,28): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'Derived1.Derived2' // public void Method(List> A, List>[] B, List C, Outer>>.Inner>>.Interface, T> D) - Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Derived1").WithLocation(37, 28), + Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "Derived1.Derived2").WithLocation(37, 28), // (27,32): error CS0535: 'Derived1.Derived2' does not implement interface member 'Outer>>.Inner>>.Interface>.Method(System.Collections.Generic.List>, System.Collections.Generic.List>[], System.Collections.Generic.List, Outer>>.Inner>>.Interface, K>)' // public class Derived2 : Outer>>.Inner>>.Interface> Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Outer>>.Inner>>.Interface>").WithArguments("Derived1.Derived2", "Outer>>.Inner>>.Interface>.Method(System.Collections.Generic.List>, System.Collections.Generic.List>[], System.Collections.Generic.List, Outer>>.Inner>>.Interface, K>)").WithLocation(27, 32), From 048e179f7a65212a8287d584f3389eb140341094 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Thu, 20 Mar 2025 11:07:01 -0700 Subject: [PATCH 2/5] Remove an extra empty line --- src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs index 73e783a5e9fcf..879918be7fa4b 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -22507,7 +22507,6 @@ static int M(int P) ); } - [Fact] public void NameConflict_29_WithStaticTypeTypeParameter() { From 57cc9797491257b4f13ba4dbc9ca47da3f6430e7 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Thu, 20 Mar 2025 11:57:53 -0700 Subject: [PATCH 3/5] Optimize --- .../Portable/Symbols/Source/SourceMemberContainerSymbol.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 84df2fa40edd1..e0d4f0bc08d5c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -2211,7 +2211,7 @@ private void ReportMethodSignatureCollision(BindingDiagnosticBag diagnostics, Me private void CheckIndexerNameConflicts(BindingDiagnosticBag diagnostics, Dictionary, ImmutableArray> membersByName) { PooledHashSet? typeParameterNames = null; - if (this.Arity > 0) + if (this.Arity > 0 && !IsExtension) { typeParameterNames = PooledHashSet.GetInstance(); foreach (TypeParameterSymbol typeParameter in this.TypeParameters) @@ -2242,7 +2242,7 @@ private void CheckIndexerNameConflicts(BindingDiagnosticBag diagnostics, Diction // Also check for collisions with type parameters, which aren't in the member map. // NOTE: Accessors have normal names and are handled in CheckTypeParameterNameConflicts. - if (typeParameterNames != null && !IsExtension) + if (typeParameterNames != null) { string indexerName = indexer.MetadataName; if (typeParameterNames.Contains(indexerName)) From e8db8cab10796701b46364fd87ea78a0f3771e86 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Thu, 20 Mar 2025 14:53:41 -0700 Subject: [PATCH 4/5] Adjust AssertMemberExposure check --- .../Portable/Symbols/Source/SourceMemberContainerSymbol.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index e0d4f0bc08d5c..6c2235f9c4517 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -1711,6 +1711,10 @@ internal void AssertMemberExposure(Symbol member, bool forDiagnostics = false) { member = implementation; // This is a workaround for https://github.com/dotnet/roslyn/issues/76870, remove once the issue is addressed. } + else if (member is SynthesizedExtensionMarker) + { + return; + } var membersAndInitializers = Volatile.Read(ref _lazyMembersAndInitializers); From b467715751f9ad260161d70de6104fbe27f1f438 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Thu, 20 Mar 2025 20:21:44 -0700 Subject: [PATCH 5/5] PR feedback --- .../Portable/Binder/Binder_NameConflicts.cs | 2 +- .../Binder/WithExtensionParameterBinder.cs | 2 - .../Test/Emit3/Semantics/ExtensionTests.cs | 109 +++++++++++++++++- 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs b/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs index a270498a380c5..26733eb3a9949 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_NameConflicts.cs @@ -69,7 +69,7 @@ internal void ValidateParameterNameConflicts( { if (tp.ContainingSymbol is NamedTypeSymbol { IsExtension: true }) { - if (p.ContainingSymbol != (object)tp.ContainingSymbol) + if (p.ContainingSymbol != (object)tp.ContainingSymbol) // Otherwise, SynthesizedExtensionMarker is going to report an error about this conflict { diagnostics.Add(ErrorCode.ERR_LocalSameNameAsExtensionTypeParameter, GetLocation(p), name); } diff --git a/src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs index e25cfc8b8f993..870e610d0f1b2 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithExtensionParameterBinder.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.CSharp.Symbols; using Roslyn.Utilities; diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs index 879918be7fa4b..d6cda8c4edb96 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -21872,6 +21872,22 @@ static int T() { static int T => T; } + + extension(C6 p) + { + int P => 0; + } + + extension(C7 p) + { + [System.Runtime.CompilerServices.IndexerName("Indexer")] + int this[int x] => 0; + } + + extension(C8 p) + { + int this[int x] => 0; + } } class C1 {} @@ -21879,6 +21895,9 @@ class C2 {} class C3 {} class C4 {} class C5 {} +class C6 {} +class C7 {} +class C8 {} """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( @@ -21961,6 +21980,22 @@ static int P1 } } } + + extension(int[] get_P) + { + int P => 0; + } + + extension(long[] get_Indexer) + { + [System.Runtime.CompilerServices.IndexerName("Indexer")] + int this[int x] => 0; + } + + extension(byte[] get_Item) + { + int this[int x] => 0; + } } """; var comp = CreateCompilation(src); @@ -22077,6 +22112,7 @@ static class Extensions void M2(int p){} static void M3(int p){} int this[int p] => 0; + void M3(int p2, int p2) {} } } """; @@ -22091,7 +22127,10 @@ static void M3(int p){} Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(6, 28), // (7,22): error CS9509: 'p': a parameter, local variable, or local function cannot have the same name as an extension parameter // int this[int p] => 0; - Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(7, 22) + Diagnostic(ErrorCode.ERR_LocalSameNameAsExtensionParameter, "p").WithArguments("p").WithLocation(7, 22), + // (8,29): error CS0100: The parameter name 'p2' is a duplicate + // void M3(int p2, int p2) {} + Diagnostic(ErrorCode.ERR_DuplicateParamName, "p2").WithArguments("p2").WithLocation(8, 29) ); } @@ -22852,6 +22891,46 @@ int M2(int x = p) ); } + [Theory] + [CombinatorialData] + public void ReceiverParameterScope_11_InNestedType(bool isStatic) + { + var modifier = isStatic ? "static" : ""; + + var src = @" +static class Extensions +{ + extension(int p) + { + class Nested + { + " + modifier + @" + int M2() + { + return p; + } + + " + modifier + @" + string M3() + { + return nameof(p); + } + } + } +} +"; + var comp = CreateCompilation(src); + + comp.VerifyEmitDiagnostics( + // (6,15): error CS9501: Extension declarations can include only methods or properties + // class Nested + Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(6, 15), + // (11,24): error CS9512: Cannot use extension parameter 'int p' in this context. + // return p; + Diagnostic(ErrorCode.ERR_InvalidExtensionParameterReference, "p").WithArguments("int p").WithLocation(11, 24) + ); + } + [Fact(Skip = "Cycle")] // PROTOTYPE: There is a cycle due to the attribute public void CycleInAttribute_01() { @@ -27485,6 +27564,34 @@ static class Nested { } Assert.Empty(model.LookupNamespacesAndTypes(position: 0, o, name: null)); } + [Fact] + public void LookupSymbols_ExtensionParameter() + { + var src = """ +public static class E +{ + extension(object o) + { + } +} +"""; + + var comp = CreateCompilation(src); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + int position = extension.OpenBraceToken.EndPosition; + AssertEqualAndNoDuplicates(["System.Object o"], model.LookupSymbols(position, null, name: "o").ToTestDisplayStrings()); + AssertEx.Equal("System.Object o", model.LookupSymbols(position, null, name: null).OfType().Single().ToTestDisplayString()); + Assert.Empty(model.LookupNamespacesAndTypes(position, null, name: "o")); + + position = extension.OpenBraceToken.Position; + Assert.Empty(model.LookupSymbols(position, null, name: "o")); + Assert.Empty(model.LookupSymbols(position, null, name: null).OfType()); + } + [Fact] public void GetMemberGroup_01() {