Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for CompilerFeatureRequiredAttribute #61113

Merged
merged 18 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -7133,4 +7133,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="IDS_FeatureRelaxedShiftOperator" xml:space="preserve">
<value>relaxed shift operator</value>
</data>
<data name="ERR_UnsupportedCompilerFeature" xml:space="preserve">
<value>'{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler.</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2087,5 +2087,6 @@ internal enum ErrorCode
ERR_RequiredMembersBaseTypeInvalid = 9509,
ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers = 9510,
ERR_NewConstraintCannotHaveRequiredMembers = 9511,
ERR_UnsupportedCompilerFeature = 9512,
}
}
10 changes: 2 additions & 8 deletions src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -307,20 +307,14 @@ internal bool CalculateUseSiteDiagnostic(ref UseSiteInfo<AssemblySymbol> result)
return false;
}

protected override int HighestPriorityUseSiteError
{
get
{
return (int)ErrorCode.ERR_BindToBogus;
}
}
protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BindToBogus;

public sealed override bool HasUnsupportedMetadata
{
get
{
DiagnosticInfo? info = GetUseSiteInfo().DiagnosticInfo;
return (object?)info != null && info.Code == (int)ErrorCode.ERR_BindToBogus;
return (object?)info != null && info.Code is (int)ErrorCode.ERR_BindToBogus or (int)ErrorCode.ERR_UnsupportedCompilerFeature;
}
}

Expand Down
12 changes: 3 additions & 9 deletions src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,22 +373,16 @@ internal bool CalculateUseSiteDiagnostic(ref UseSiteInfo<AssemblySymbol> result)
}

/// <summary>
/// Return error code that has highest priority while calculating use site error for this symbol.
/// Returns true if the error code is highest priority while calculating use site error for this symbol.
/// </summary>
protected override int HighestPriorityUseSiteError
{
get
{
return (int)ErrorCode.ERR_BindToBogus;
}
}
protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BindToBogus;

public sealed override bool HasUnsupportedMetadata
{
get
{
DiagnosticInfo info = GetUseSiteInfo().DiagnosticInfo;
return (object)info != null && info.Code == (int)ErrorCode.ERR_BindToBogus;
return (object)info != null && info.Code is (int)ErrorCode.ERR_BindToBogus or (int)ErrorCode.ERR_UnsupportedCompilerFeature;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE
Expand Down Expand Up @@ -63,6 +64,10 @@ internal sealed class PEAssemblySymbol : MetadataOrSourceAssemblySymbol
/// </summary>
private ImmutableArray<CSharpAttributeData> _lazyCustomAttributes;

#nullable enable
private DiagnosticInfo? _lazyCachedCompilerFeatureRequiredDiagnosticInfo = CSDiagnosticInfo.EmptyErrorInfo;
#nullable disable

internal PEAssemblySymbol(PEAssembly assembly, DocumentationProvider documentationProvider, bool isLinked, MetadataImportOptions importOptions)
{
Debug.Assert(assembly != null);
Expand Down Expand Up @@ -280,5 +285,22 @@ internal PEModuleSymbol PrimaryModule
}

public override AssemblyMetadata GetMetadata() => _assembly.GetNonDisposableMetadata();

#nullable enable
internal DiagnosticInfo? GetCompilerFeatureRequiredDiagnostic()
{
if (_lazyCachedCompilerFeatureRequiredDiagnosticInfo == CSDiagnosticInfo.EmptyErrorInfo)
{
Interlocked.CompareExchange(
ref _lazyCachedCompilerFeatureRequiredDiagnosticInfo,
PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, PrimaryModule, this.Assembly.Handle, CompilerFeatureRequiredFeatures.None, new MetadataDecoder(PrimaryModule)),
CSDiagnosticInfo.EmptyErrorInfo);
}

return _lazyCachedCompilerFeatureRequiredDiagnosticInfo;
}

public override bool HasUnsupportedMetadata
=> GetCompilerFeatureRequiredDiagnostic()?.Code == (int)ErrorCode.ERR_UnsupportedCompilerFeature || base.HasUnsupportedMetadata;
}
}
20 changes: 20 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -468,10 +468,30 @@ internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo()
{
UseSiteInfo<AssemblySymbol> result = new UseSiteInfo<AssemblySymbol>(primaryDependency);
CalculateUseSiteDiagnostic(ref result);
deriveCompilerFeatureRequiredUseSiteInfo(ref result);
_lazyCachedUseSiteInfo.Initialize(primaryDependency, result);
}

return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency);

void deriveCompilerFeatureRequiredUseSiteInfo(ref UseSiteInfo<AssemblySymbol> result)
{
var containingType = (PENamedTypeSymbol)ContainingType;
PEModuleSymbol containingPEModule = _containingType.ContainingPEModule;
var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(
this,
containingPEModule,
Handle,
allowedFeatures: CompilerFeatureRequiredFeatures.None,
new MetadataDecoder(containingPEModule, containingType));

diag ??= containingType.GetCompilerFeatureRequiredDiagnostic();

if (diag != null)
{
result = new UseSiteInfo<AssemblySymbol>(diag);
}
}
}

internal override ObsoleteAttributeData ObsoleteAttributeData
Expand Down
20 changes: 20 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -590,10 +590,30 @@ internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo()
{
UseSiteInfo<AssemblySymbol> result = new UseSiteInfo<AssemblySymbol>(primaryDependency);
CalculateUseSiteDiagnostic(ref result);
deriveCompilerFeatureRequiredUseSiteInfo(ref result);
_lazyCachedUseSiteInfo.Initialize(primaryDependency, result);
}

return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency);

void deriveCompilerFeatureRequiredUseSiteInfo(ref UseSiteInfo<AssemblySymbol> result)
{
var containingType = (PENamedTypeSymbol)ContainingType;
PEModuleSymbol containingPEModule = _containingType.ContainingPEModule;
var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(
this,
containingPEModule,
Handle,
allowedFeatures: CompilerFeatureRequiredFeatures.None,
new MetadataDecoder(containingPEModule, containingType));

diag ??= containingType.GetCompilerFeatureRequiredDiagnostic();

if (diag != null)
{
result = new UseSiteInfo<AssemblySymbol>(diag);
}
}
}

internal override ObsoleteAttributeData ObsoleteAttributeData
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,7 @@ internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo()
CalculateUseSiteDiagnostic(ref result);

var diagnosticInfo = result.DiagnosticInfo;
MergeUseSiteDiagnostics(ref diagnosticInfo, DeriveCompilerFeatureRequiredDiagnostic());
EnsureTypeParametersAreLoaded(ref diagnosticInfo);
if (diagnosticInfo == null && GetUnmanagedCallersOnlyAttributeData(forceComplete: true) is UnmanagedCallersOnlyAttributeData data)
{
Expand All @@ -1380,6 +1381,44 @@ internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo()
return GetCachedUseSiteInfo();
}

private DiagnosticInfo DeriveCompilerFeatureRequiredDiagnostic()
{
var containingModule = _containingType.ContainingPEModule;
var decoder = new MetadataDecoder(containingModule, this);
var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, containingModule, Handle, allowedFeatures: MethodKind == MethodKind.Constructor ? CompilerFeatureRequiredFeatures.RequiredMembers : CompilerFeatureRequiredFeatures.None, decoder);

if (diag != null)
{
return diag;
}

diag = Signature.ReturnParam.DeriveCompilerFeatureRequiredDiagnostic(decoder);
if (diag != null)
{
return diag;
}

foreach (var param in Parameters)
{
diag = ((PEParameterSymbol)param).DeriveCompilerFeatureRequiredDiagnostic(decoder);
if (diag != null)
{
return diag;
}
}

foreach (var typeParam in TypeParameters)
{
diag = ((PETypeParameterSymbol)typeParam).DeriveCompilerFeatureRequiredDiagnostic(decoder);
if (diag != null)
{
return diag;
}
}

return _containingType.GetCompilerFeatureRequiredDiagnostic();
}

private UseSiteInfo<AssemblySymbol> GetCachedUseSiteInfo()
{
return (_uncommonFields?._lazyCachedUseSiteInfo ?? default).ToUseSiteInfo(PrimaryDependency);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ private enum NullableMemberMetadata

private NullableMemberMetadata _lazyNullableMemberMetadata;

#nullable enable
private DiagnosticInfo? _lazyCachedCompilerFeatureRequiredDiagnosticInfo = CSDiagnosticInfo.EmptyErrorInfo;
#nullable disable

internal PEModuleSymbol(PEAssemblySymbol assemblySymbol, PEModule module, MetadataImportOptions importOptions, int ordinal)
: this((AssemblySymbol)assemblySymbol, module, importOptions, ordinal)
{
Expand Down Expand Up @@ -755,5 +759,22 @@ internal bool ShouldDecodeNullableAttributes(Symbol symbol)

return false;
}

#nullable enable
internal DiagnosticInfo? GetCompilerFeatureRequiredDiagnostic()
{
if (_lazyCachedCompilerFeatureRequiredDiagnosticInfo == CSDiagnosticInfo.EmptyErrorInfo)
{
Interlocked.CompareExchange(
ref _lazyCachedCompilerFeatureRequiredDiagnosticInfo,
PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, this, Token, CompilerFeatureRequiredFeatures.None, new MetadataDecoder(this)),
CSDiagnosticInfo.EmptyErrorInfo);
}

return _lazyCachedCompilerFeatureRequiredDiagnosticInfo ?? (_assemblySymbol as PEAssemblySymbol)?.GetCompilerFeatureRequiredDiagnostic();
}

public override bool HasUnsupportedMetadata
=> GetCompilerFeatureRequiredDiagnostic()?.Code == (int)ErrorCode.ERR_UnsupportedCompilerFeature || base.HasUnsupportedMetadata;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ internal static PENamedTypeSymbol Create(

if (mrEx != null)
{
result._lazyCachedUseSiteInfo.Initialize(new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result));
result._lazyCachedUseSiteInfo.Initialize(result.DeriveCompilerFeatureRequiredDiagnostic() ?? new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result));
}

return result;
Expand Down Expand Up @@ -261,7 +261,7 @@ internal static PENamedTypeSymbol Create(

if (mrEx != null || metadataArity < containerMetadataArity)
{
result._lazyCachedUseSiteInfo.Initialize(new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result));
result._lazyCachedUseSiteInfo.Initialize(result.DeriveCompilerFeatureRequiredDiagnostic() ?? new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result));
}

return result;
Expand Down Expand Up @@ -331,7 +331,7 @@ private PENamedTypeSymbol(

if (makeBad)
{
_lazyCachedUseSiteInfo.Initialize(new CSDiagnosticInfo(ErrorCode.ERR_BogusType, this));
_lazyCachedUseSiteInfo.Initialize(DeriveCompilerFeatureRequiredDiagnostic() ?? new CSDiagnosticInfo(ErrorCode.ERR_BogusType, this));
}
}

Expand Down Expand Up @@ -2024,7 +2024,14 @@ internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo()

protected virtual DiagnosticInfo GetUseSiteDiagnosticImpl()
{
DiagnosticInfo diagnostic = null;
// GetCompilerFeatureRequiredDiagnostic depends on UnsupportedCompilerFeature being the highest priority diagnostic, or it will return incorrect
333fred marked this conversation as resolved.
Show resolved Hide resolved
// results and assert in Debug mode.
DiagnosticInfo diagnostic = DeriveCompilerFeatureRequiredDiagnostic();

if (diagnostic != null)
{
return diagnostic;
}

if (!MergeUseSiteDiagnostics(ref diagnostic, CalculateUseSiteDiagnostic()))
{
Expand Down Expand Up @@ -2060,6 +2067,45 @@ protected virtual DiagnosticInfo GetUseSiteDiagnosticImpl()
return diagnostic;
}

#nullable enable
internal DiagnosticInfo? GetCompilerFeatureRequiredDiagnostic()
{
var useSiteInfo = GetUseSiteInfo();
if (useSiteInfo.DiagnosticInfo is { Code: (int)ErrorCode.ERR_UnsupportedCompilerFeature } diag)
{
return diag;
}

Debug.Assert(DeriveCompilerFeatureRequiredDiagnostic() is null);
return null;
}

private DiagnosticInfo? DeriveCompilerFeatureRequiredDiagnostic()
{
var decoder = new MetadataDecoder(ContainingPEModule, this);
var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, ContainingPEModule, Handle, allowedFeatures: IsRefLikeType ? CompilerFeatureRequiredFeatures.RefStructs : CompilerFeatureRequiredFeatures.None, decoder);

if (diag != null)
{
return diag;
}

foreach (var typeParameter in TypeParameters)
{
diag = ((PETypeParameterSymbol)typeParameter).DeriveCompilerFeatureRequiredDiagnostic(decoder);

if (diag != null)
{
return diag;
}
}

return ContainingType is PENamedTypeSymbol containingType
? containingType.GetCompilerFeatureRequiredDiagnostic()
: ContainingPEModule.GetCompilerFeatureRequiredDiagnostic();
}
#nullable disable

internal string DefaultMemberName
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1068,5 +1068,25 @@ public sealed override bool Equals(Symbol other, TypeCompareKind compareKind)
nps.Equals(this, compareKind) :
base.Equals(other, compareKind);
}

#nullable enable
internal DiagnosticInfo? DeriveCompilerFeatureRequiredDiagnostic(MetadataDecoder decoder)
=> PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, (PEModuleSymbol)ContainingModule, Handle, allowedFeatures: CompilerFeatureRequiredFeatures.None, decoder);

public override bool HasUnsupportedMetadata
{
get
{
var containingModule = (PEModuleSymbol)ContainingModule;
var decoder = ContainingSymbol switch
{
PEMethodSymbol method => new MetadataDecoder(containingModule, method),
PEPropertySymbol => new MetadataDecoder(containingModule, (PENamedTypeSymbol)ContainingType),
_ => throw ExceptionUtilities.UnexpectedValue(this.ContainingSymbol.Kind)
};

return DeriveCompilerFeatureRequiredDiagnostic(decoder) is { Code: (int)ErrorCode.ERR_UnsupportedCompilerFeature } || base.HasUnsupportedMetadata;
333fred marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
Loading