Skip to content

Commit

Permalink
Adjust the way nullable annotations are represented in metadata.
Browse files Browse the repository at this point in the history
Closes dotnet#30075.
Closes dotnet#30065.
Closes dotnet#29594.
  • Loading branch information
AlekseyTs committed Nov 15, 2018
1 parent e63f327 commit 934f8da
Show file tree
Hide file tree
Showing 109 changed files with 666 additions and 3,071 deletions.
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ internal virtual Symbol ContainingMemberOrLambda
/// <summary>
/// Are we in a context where un-annotated types should be interpreted as non-null?
/// </summary>
internal Symbol NonNullTypesContext => ContainingMember().OriginalDefinition;
internal INonNullTypesContext NonNullTypesContext => (Flags & BinderFlags.InEEMethodBinder) == 0 ? ContainingMember().OriginalDefinition : NonNullTypesTrueContext.Instance;

/// <summary>
/// Is the contained code within a member method body?
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/BinderFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ internal enum BinderFlags : uint
/// </summary>
InContextualAttributeBinder = 1 << 29,

/// <summary>
/// Are we binding for the purpose of an Expression Evaluator
/// </summary>
InEEMethodBinder = 1 << 30,

// Groups

AllClearedAtExecutableCodeBoundary = InLockBody | InCatchBlock | InCatchFilter | InFinallyBlock | InTryBlockOfTryCatch | InNestedFinallyBlock,
Expand Down
30 changes: 12 additions & 18 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1494,28 +1494,22 @@ internal Symbol ResultSymbol(
var srcSymbol = symbols[best.Index];
var mdSymbol = symbols[secondBest.Index];

object arg0;

if (best.IsFromSourceModule)
{
arg0 = srcSymbol.Locations.First().SourceTree.FilePath;
}
else
{
Debug.Assert(best.IsFromAddedModule);
arg0 = srcSymbol.ContainingModule;
}

//if names match, arities match, and containing symbols match (recursively), ...
if (srcSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat) ==
mdSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat))
{
if (srcSymbol.Equals(Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_NonNullTypesAttribute)))
{
// Silently prefer the injected symbol
return originalSymbols[best.Index];
}

object arg0;
if (best.IsFromSourceModule)
{
SyntaxTree tree = srcSymbol.Locations.FirstOrNone().SourceTree;
arg0 = tree != null ? (object)tree.FilePath : MessageID.IDS_InjectedDeclaration.Localize();
}
else
{
Debug.Assert(best.IsFromAddedModule);
arg0 = srcSymbol.ContainingModule;
}

if (srcSymbol.Kind == SymbolKind.Namespace && mdSymbol.Kind == SymbolKind.NamedType)
{
// ErrorCode.WRN_SameFullNameThisNsAgg: The namespace '{1}' in '{0}' conflicts with the imported type '{3}' in '{2}'. Using the namespace defined in '{0}'.
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType)

if (!returnType.IsNull)
{
if (returnType.ContainsNullableReferenceTypes())
if (returnType.NeedsNullableAttribute())
{
binder.Compilation.EnsureNullableAttributeExists(diagnostics, lambdaSymbol.DiagnosticLocation, modifyCompilation: false);
// Note: we don't need to warn on annotations used without NonNullTypes context for lambdas, as this is handled in binding already
Expand Down
20 changes: 1 addition & 19 deletions src/Compilers/CSharp/Portable/CSharpResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4284,9 +4284,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="IDS_Text" xml:space="preserve">
<value>&lt;text&gt;</value>
</data>
<data name="IDS_InjectedDeclaration" xml:space="preserve">
<value>injected declaration</value>
</data>
<data name="IDS_FeatureNullPropagatingOperator" xml:space="preserve">
<value>null propagating operator</value>
</data>
Expand Down Expand Up @@ -5628,9 +5625,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_BadDynamicAwaitForEach" xml:space="preserve">
<value>Cannot use a collection of dynamic type in an asynchronous foreach</value>
</data>
<data name="ERR_ExplicitNonNullTypesAttribute" xml:space="preserve">
<value>Explicit application of 'System.Runtime.CompilerServices.NonNullTypesAttribute' is not allowed.</value>
</data>
<data name="ERR_NullableDirectiveQualifierExpected" xml:space="preserve">
<value>Expected enable or disable</value>
</data>
Expand Down
118 changes: 40 additions & 78 deletions src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ internal abstract class PEAssemblyBuilderBase : PEModuleBuilder, Cci.IAssemblyRe
private readonly ImmutableArray<NamedTypeSymbol> _additionalTypes;
private ImmutableArray<Cci.IFileReference> _lazyFiles;

private SynthesizedEmbeddedAttributeSymbol _lazyEmbeddedAttribute;
private SynthesizedEmbeddedAttributeSymbol _lazyIsReadOnlyAttribute;
private SynthesizedEmbeddedAttributeSymbol _lazyIsByRefLikeAttribute;
private SynthesizedEmbeddedAttributeSymbol _lazyIsUnmanagedAttribute;
private SynthesizedEmbeddedAttributeSymbol _lazyNullableAttribute;
private ImmutableArray<NamedTypeSymbol> _lazyInjectedTypes;
private bool _needsNonNullTypesAttribute;
private bool _needsEmbeddedAttribute;

/// <summary>
/// The behavior of the C# command-line compiler is as follows:
Expand Down Expand Up @@ -63,18 +61,6 @@ public PEAssemblyBuilderBase(
AssemblyOrModuleSymbolToModuleRefMap.Add(sourceAssembly, this);
}

protected override void EnsureNonNullTypesAttributeExists()
{
Debug.Assert(!InjectedSymbolsAreFrozen);
_needsNonNullTypesAttribute = true;
}

protected override void EnsureEmbeddedAttributeExists()
{
Debug.Assert(!InjectedSymbolsAreFrozen);
_needsEmbeddedAttribute = true;
}

public override ISourceAssemblySymbolInternal SourceAssemblyOpt => _sourceAssembly;

internal override ImmutableArray<NamedTypeSymbol> GetAdditionalTopLevelTypes(DiagnosticBag diagnostics)
Expand All @@ -87,6 +73,10 @@ internal override ImmutableArray<NamedTypeSymbol> GetEmbeddedTypes(DiagnosticBag
var builder = ArrayBuilder<NamedTypeSymbol>.GetInstance();

CreateEmbeddedAttributesIfNeeded(diagnostics);
if ((object)_lazyEmbeddedAttribute != null)
{
builder.Add(_lazyEmbeddedAttribute);
}

if ((object)_lazyIsReadOnlyAttribute != null)
{
Expand Down Expand Up @@ -182,6 +172,15 @@ protected override void AddEmbeddedResourcesFromAddedModules(ArrayBuilder<Cci.Ma
public AssemblyIdentity Identity => _sourceAssembly.Identity;
public Version AssemblyVersionPattern => _sourceAssembly.AssemblyVersionPattern;

internal override SynthesizedAttributeData SynthesizeEmbeddedAttribute()
{
// _lazyEmbeddedAttribute should have been created before calling this method.
return new SynthesizedAttributeData(
_lazyEmbeddedAttribute.Constructors[0],
ImmutableArray<TypedConstant>.Empty,
ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty);
}

internal override SynthesizedAttributeData SynthesizeNullableAttribute(WellKnownMember member, ImmutableArray<TypedConstant> arguments)
{
if ((object)_lazyNullableAttribute != null)
Expand Down Expand Up @@ -239,6 +238,8 @@ private void CreateEmbeddedAttributesIfNeeded(DiagnosticBag diagnostics)
{
if (this.NeedsGeneratedIsReadOnlyAttribute)
{
CreateEmbeddedAttributeItselfIfNeeded(diagnostics);

CreateEmbeddedAttributeIfNeeded(
ref _lazyIsReadOnlyAttribute,
diagnostics,
Expand All @@ -247,6 +248,8 @@ private void CreateEmbeddedAttributesIfNeeded(DiagnosticBag diagnostics)

if (this.NeedsGeneratedIsByRefLikeAttribute)
{
CreateEmbeddedAttributeItselfIfNeeded(diagnostics);

CreateEmbeddedAttributeIfNeeded(
ref _lazyIsByRefLikeAttribute,
diagnostics,
Expand All @@ -255,6 +258,8 @@ private void CreateEmbeddedAttributesIfNeeded(DiagnosticBag diagnostics)

if (this.NeedsGeneratedIsUnmanagedAttribute)
{
CreateEmbeddedAttributeItselfIfNeeded(diagnostics);

CreateEmbeddedAttributeIfNeeded(
ref _lazyIsUnmanagedAttribute,
diagnostics,
Expand All @@ -263,78 +268,32 @@ private void CreateEmbeddedAttributesIfNeeded(DiagnosticBag diagnostics)

if (this.NeedsGeneratedNullableAttribute)
{
CreateEmbeddedAttributeItselfIfNeeded(diagnostics);

CreateEmbeddedAttributeIfNeeded(
ref _lazyNullableAttribute,
diagnostics,
AttributeDescription.NullableAttribute,
GetAdditionalNullableAttributeConstructors);
GetNullableAttributeConstructors);
}
}

protected override bool InjectedSymbolsAreFrozen => !_lazyInjectedTypes.IsDefault;

/// <summary>
/// Get injected types that are needed (ie. were used) and report the diagnostics they held onto (only once).
/// </summary>
protected sealed override ImmutableArray<NamedTypeSymbol> GetInjectedTypes(DiagnosticBag diagnostics)
private void CreateEmbeddedAttributeItselfIfNeeded(DiagnosticBag diagnostics)
{
if (!_lazyInjectedTypes.IsDefault)
{
return _lazyInjectedTypes;
}

if (_needsNonNullTypesAttribute)
{
EnsureEmbeddedAttributeExists();
}

ArrayBuilder<NamedTypeSymbol> builder = null;
if (_needsEmbeddedAttribute)
{
addInjectedAttribute(WellKnownType.Microsoft_CodeAnalysis_EmbeddedAttribute, canUseFromSource: false);
}

if (_needsNonNullTypesAttribute)
{
addInjectedAttribute(WellKnownType.System_Runtime_CompilerServices_NonNullTypesAttribute, canUseFromSource: true);
}

var result = builder is null ? ImmutableArray<NamedTypeSymbol>.Empty : builder.ToImmutableAndFree();
ImmutableInterlocked.InterlockedInitialize(ref _lazyInjectedTypes, result);
return _lazyInjectedTypes;

void addInjectedAttribute(WellKnownType wellKnownType, bool canUseFromSource)
{
NamedTypeSymbol attribute = Compilation.GetWellKnownType(wellKnownType);

if (attribute is InjectedAttributeSymbol injected)
{
injected.AddDiagnostics(diagnostics);
builder = builder ?? ArrayBuilder<NamedTypeSymbol>.GetInstance();
builder.Add(attribute);
}
else if (attribute.IsErrorType())
{
diagnostics.Add(attribute.GetUseSiteDiagnostic(), NoLocation.Singleton);
}
else if (!canUseFromSource)
{
// if the attribute is defined in source, we can't embed it (we'll produce a diagnostic)
diagnostics.Add(ErrorCode.ERR_TypeReserved, attribute.Locations[0], attribute);
}
}
CreateEmbeddedAttributeIfNeeded(
ref _lazyEmbeddedAttribute,
diagnostics,
AttributeDescription.CodeAnalysisEmbeddedAttribute);
}

private void CreateEmbeddedAttributeIfNeeded(
ref SynthesizedEmbeddedAttributeSymbol symbol,
DiagnosticBag diagnostics,
AttributeDescription description,
Func<CSharpCompilation, NamedTypeSymbol, DiagnosticBag, ImmutableArray<MethodSymbol>> getAdditionalConstructors = null)
Func<CSharpCompilation, NamedTypeSymbol, DiagnosticBag, ImmutableArray<MethodSymbol>> getConstructors = null)
{
if ((object)symbol == null)
{
EnsureEmbeddedAttributeExists();

var attributeMetadataName = MetadataTypeName.FromFullName(description.FullName);
var userDefinedAttribute = _sourceAssembly.SourceModule.LookupTopLevelMetadataType(ref attributeMetadataName);
Debug.Assert((object)userDefinedAttribute.ContainingModule == _sourceAssembly.SourceModule);
Expand All @@ -344,25 +303,28 @@ private void CreateEmbeddedAttributeIfNeeded(
diagnostics.Add(ErrorCode.ERR_TypeReserved, userDefinedAttribute.Locations[0], description.FullName);
}

symbol = new SynthesizedEmbeddedAttributeSymbol(description, _sourceAssembly.DeclaringCompilation, getAdditionalConstructors, diagnostics);
symbol = new SynthesizedEmbeddedAttributeSymbol(description, _sourceAssembly.DeclaringCompilation, getConstructors, diagnostics);
}
}

private static ImmutableArray<MethodSymbol> GetAdditionalNullableAttributeConstructors(
private static ImmutableArray<MethodSymbol> GetNullableAttributeConstructors(
CSharpCompilation compilation,
NamedTypeSymbol containingType,
DiagnosticBag diagnostics)
{
var boolType = compilation.GetSpecialType(SpecialType.System_Boolean);
Binder.ReportUseSiteDiagnostics(boolType, diagnostics, Location.None);
var boolArray = TypeSymbolWithAnnotations.Create(
var byteType = TypeSymbolWithAnnotations.Create(compilation.GetSpecialType(SpecialType.System_Byte));
Binder.ReportUseSiteDiagnostics(byteType.TypeSymbol, diagnostics, Location.None);
var byteArray = TypeSymbolWithAnnotations.Create(
ArrayTypeSymbol.CreateSZArray(
boolType.ContainingAssembly,
TypeSymbolWithAnnotations.Create(boolType)));
byteType.TypeSymbol.ContainingAssembly,
byteType));
return ImmutableArray.Create<MethodSymbol>(
new SynthesizedEmbeddedAttributeConstructorSymbol(
containingType,
m => ImmutableArray.Create(SynthesizedParameterSymbol.Create(m, boolArray, 0, RefKind.None))));
m => ImmutableArray.Create(SynthesizedParameterSymbol.Create(m, byteType, 0, RefKind.None))),
new SynthesizedEmbeddedAttributeConstructorSymbol(
containingType,
m => ImmutableArray.Create(SynthesizedParameterSymbol.Create(m, byteArray, 0, RefKind.None))));
}
}

Expand Down
Loading

0 comments on commit 934f8da

Please sign in to comment.