-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Generate readonlyattribute if it does not exist #18715
Changes from 17 commits
d01bccc
ea8e8da
389871a
45abc25
f14b9b0
72459ef
13e65c1
ddf80c5
801d046
ab6d26c
bfb6f8b
97fdd3b
6738585
b75e420
639bdb5
d2d9747
7be6b63
40748ee
f4ce74d
83f6355
f6dc461
0bc8579
7042fc6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -450,8 +450,17 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) | |
cacheKey.ParameterTypes, | ||
cacheKey.ParameterRefKinds, | ||
refKind, | ||
returnType); | ||
returnType, | ||
diagnostics); | ||
lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); | ||
|
||
if (lambdaSymbol.RefKind == CodeAnalysis.RefKind.RefReadOnly) | ||
{ | ||
binder.Compilation.EnsureIsReadOnlyAttributeExists(diagnostics, lambdaSymbol.DiagnosticLocation, modifyCompilationForRefReadOnly: false); | ||
} | ||
|
||
ParameterHelpers.EnsureIsReadOnlyAttributeExists(lambdaSymbol.Parameters, diagnostics, modifyCompilationForRefReadOnly: false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aren't we calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If these checks are necessary, is there a reason to have the checks in the caller rather than in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For lambdas and local functions, we do that two times:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there diagnostics generated here that we cannot generate in the local rewriter? If not, can we drop the checks from here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Diagnostics generated here are needed even though we are not emitting anything. We would still want to display them to the API users. |
||
|
||
block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); | ||
|
||
((ExecutableCodeBinder)lambdaBodyBinder).ValidateIteratorMethods(diagnostics); | ||
|
@@ -525,7 +534,15 @@ private void ValidateUnsafeParameters(DiagnosticBag diagnostics, ImmutableArray< | |
private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType, ImmutableArray<TypeSymbol> parameterTypes, ImmutableArray<RefKind> parameterRefKinds) | ||
{ | ||
var diagnostics = DiagnosticBag.GetInstance(); | ||
var lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameterTypes, parameterRefKinds, refKind: Microsoft.CodeAnalysis.RefKind.None, returnType: null); | ||
var lambdaSymbol = new LambdaSymbol( | ||
binder.Compilation, | ||
binder.ContainingMemberOrLambda, | ||
_unboundLambda, | ||
parameterTypes, | ||
parameterRefKinds, | ||
refKind: CodeAnalysis.RefKind.None, | ||
returnType: null, | ||
diagnostics: diagnostics); | ||
Binder lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); | ||
var block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,13 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Diagnostics; | ||
using System.Reflection; | ||
using System.Threading; | ||
using Microsoft.Cci; | ||
using Microsoft.CodeAnalysis.CSharp.Symbols; | ||
using Microsoft.CodeAnalysis.Emit; | ||
using Roslyn.Utilities; | ||
|
@@ -17,6 +20,10 @@ internal abstract class PEAssemblyBuilderBase : PEModuleBuilder, Cci.IAssemblyRe | |
private readonly ImmutableArray<NamedTypeSymbol> _additionalTypes; | ||
private ImmutableArray<Cci.IFileReference> _lazyFiles; | ||
|
||
private SynthesizedEmbeddedAttributeSymbol _lazyEmbeddedAttribute; | ||
private SynthesizedEmbeddedAttributeSymbol _lazyIsReadOnlyAttribute; | ||
private ImmutableArray<Diagnostic> _lazyEmbeddedAttributesDiagnostics; | ||
|
||
/// <summary> | ||
/// The behavior of the C# command-line compiler is as follows: | ||
/// 1) If the /out switch is specified, then the explicit assembly name is used. | ||
|
@@ -56,9 +63,24 @@ public PEAssemblyBuilderBase( | |
|
||
public override ISourceAssemblySymbolInternal SourceAssemblyOpt => _sourceAssembly; | ||
|
||
internal override ImmutableArray<NamedTypeSymbol> GetAdditionalTopLevelTypes() | ||
internal override ImmutableArray<NamedTypeSymbol> GetAdditionalTopLevelTypes(DiagnosticBag diagnostics) | ||
{ | ||
return _additionalTypes; | ||
var builder = ArrayBuilder<NamedTypeSymbol>.GetInstance(); | ||
builder.AddRange(_additionalTypes); | ||
|
||
CreateEmbeddedAttributesIfNeeded(); | ||
diagnostics.AddRange(_lazyEmbeddedAttributesDiagnostics); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is likely to cause duplication of errors. We should avoid that, we specifically avoid reporting duplicate errors in PEModuleBuilder, see _reportedErrorTypesMap for example. Please revert to the previous approach. |
||
|
||
if ((object)_lazyEmbeddedAttribute != null) | ||
{ | ||
builder.Add(_lazyEmbeddedAttribute); | ||
} | ||
if ((object)_lazyIsReadOnlyAttribute != null) | ||
{ | ||
builder.Add(_lazyIsReadOnlyAttribute); | ||
} | ||
|
||
return builder.ToImmutableAndFree(); | ||
} | ||
|
||
public sealed override IEnumerable<Cci.IFileReference> GetFiles(EmitContext context) | ||
|
@@ -131,6 +153,72 @@ protected override void AddEmbeddedResourcesFromAddedModules(ArrayBuilder<Cci.Ma | |
public override string Name => _metadataName; | ||
public AssemblyIdentity Identity => _sourceAssembly.Identity; | ||
public Version AssemblyVersionPattern => _sourceAssembly.AssemblyVersionPattern; | ||
|
||
internal override SynthesizedAttributeData SynthesizeEmbeddedAttribute() | ||
{ | ||
if ((object)_lazyEmbeddedAttribute != null) | ||
{ | ||
return new SynthesizedAttributeData( | ||
_lazyEmbeddedAttribute.Constructor, | ||
ImmutableArray<TypedConstant>.Empty, | ||
ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty); | ||
} | ||
|
||
return base.SynthesizeEmbeddedAttribute(); | ||
} | ||
|
||
protected override SynthesizedAttributeData TrySynthesizeIsReadOnlyAttribute() | ||
{ | ||
if ((object)_lazyIsReadOnlyAttribute != null) | ||
{ | ||
return new SynthesizedAttributeData( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I would expect us to return null if symbol is not from our source module. #Closed |
||
_lazyIsReadOnlyAttribute.Constructor, | ||
ImmutableArray<TypedConstant>.Empty, | ||
ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty); | ||
} | ||
|
||
return base.TrySynthesizeIsReadOnlyAttribute(); | ||
} | ||
|
||
private void CreateEmbeddedAttributesIfNeeded() | ||
{ | ||
if (_lazyEmbeddedAttributesDiagnostics.IsDefault) | ||
{ | ||
var diagnostics = DiagnosticBag.GetInstance(); | ||
|
||
if (this.NeedsGeneratedIsReadOnlyAttribute) | ||
{ | ||
CreateEmbeddedAttributeIfNeeded( | ||
ref _lazyEmbeddedAttribute, | ||
diagnostics, | ||
AttributeDescription.CodeAnalysisEmbeddedAttribute); | ||
|
||
CreateEmbeddedAttributeIfNeeded( | ||
ref _lazyIsReadOnlyAttribute, | ||
diagnostics, | ||
AttributeDescription.IsReadOnlyAttribute); | ||
} | ||
|
||
_lazyEmbeddedAttributesDiagnostics = diagnostics.ToReadOnlyAndFree(); | ||
} | ||
} | ||
|
||
private void CreateEmbeddedAttributeIfNeeded(ref SynthesizedEmbeddedAttributeSymbol symbol, DiagnosticBag diagnostics, AttributeDescription description) | ||
{ | ||
if ((object)symbol == null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there still a case where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is possibly going to be rewritten in Vlad's next PR, as there are more attributes to be generated. His feature will possibly need to generate some attributes that are generated in this PR, so the check will be necessary.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now we are adding only |
||
{ | ||
var attributeMetadataName = MetadataTypeName.FromFullName(description.FullName); | ||
var userDefinedAttribute = _sourceAssembly.SourceModule.LookupTopLevelMetadataType(ref attributeMetadataName); | ||
Debug.Assert((object)userDefinedAttribute.ContainingModule == _sourceAssembly.SourceModule); | ||
|
||
if (!(userDefinedAttribute is MissingMetadataTypeSymbol)) | ||
{ | ||
diagnostics.Add(ErrorCode.ERR_TypeReserved, userDefinedAttribute.Locations[0], description.FullName); | ||
} | ||
|
||
symbol = new SynthesizedEmbeddedAttributeSymbol(description, _sourceAssembly.DeclaringCompilation, diagnostics); | ||
} | ||
} | ||
} | ||
|
||
internal sealed class PEAssemblyBuilder : PEAssemblyBuilderBase | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have tests covering significance of this condition? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious - why "external" part makes a difference? I thought the embedded symbols are not bindable regardless of where defined.
In reply to: 113533730 [](ancestors = 113533730)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have tests that cover one condition. Adding more tests now.
edit: @VSadov I'm correcting this now. Lookup would fail if on embedded attributes defined somewhere else. If you define your own embedded attribute we would ignore it. UNLESS the compiler needs to generate one, then we will produce an error.
In reply to: 113549567 [](ancestors = 113549567,113533730)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you point me to a test that demonstrates significance of the first condition?
In reply to: 114024707 [](ancestors = 114024707,113549567,113533730)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check
AttributeTests_Embedded.cs
:ReferencingEmbeddedAttributesFromADifferentAssemblyFails_Internal
ReferencingEmbeddedAttributesFromADifferentAssemblyFails_Public
and
EmbeddedAttributeInSourceShouldTriggerAnErrorIfCompilerNeedsToGenerateOne
In reply to: 115050349 [](ancestors = 115050349,114024707,113549567,113533730)