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

File types emit #61646

Merged
merged 14 commits into from
Jun 29, 2022
Merged
3 changes: 2 additions & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2493,7 +2493,8 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name

// NOTE: This won't work if the type isn't using CLS-style generic naming (i.e. `arity), but this code is
// only intended to improve diagnostic messages, so false negatives in corner cases aren't a big deal.
var metadataName = MetadataHelpers.ComposeAritySuffixedMetadataName(name, arity);
// File types can't be forwarded, so we won't attempt to determine a file identifier to attach to the metadata name.
var metadataName = MetadataHelpers.ComposeAritySuffixedMetadataName(name, arity, associatedFileIdentifier: null);
var fullMetadataName = MetadataHelpers.BuildQualifiedName(qualifierOpt?.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat), metadataName);
var result = GetForwardedToAssembly(fullMetadataName, diagnostics, location);
if ((object)result != null)
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -7112,6 +7112,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_FileTypeBase" xml:space="preserve">
<value>File type '{0}' cannot be used as a base type of non-file type '{1}'.</value>
</data>
<data name="ERR_FileTypeNested" xml:space="preserve">
<value>File type '{0}' must be defined in a top level type; '{0}' is a nested type.</value>
</data>
<data name="IDS_FeatureUnsignedRightShift" xml:space="preserve">
<value>unsigned right shift</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ bool Cci.INamedTypeReference.MangleName
}
}

#nullable enable
string? Cci.INamedTypeReference.AssociatedFileIdentifier
{
get
{
return UnderlyingNamedType.AssociatedFileIdentifier();
}
}
#nullable disable

string Cci.INamedEntity.Name
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,16 @@ bool Cci.INamedTypeReference.MangleName
}
}

#nullable enable
string? Cci.INamedTypeReference.AssociatedFileIdentifier
{
get
{
return AdaptedNamedTypeSymbol.AssociatedFileIdentifier();
}
}
#nullable disable

string Cci.INamedEntity.Name
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ private void ReportExportedTypeNameCollisions(ImmutableArray<Cci.ExportedType> e
// exported types are not emitted in EnC deltas (hence generation 0):
string fullEmittedName = MetadataHelpers.BuildQualifiedName(
((Cci.INamespaceTypeReference)type.GetCciAdapter()).NamespaceName,
Cci.MetadataWriter.GetMangledName(type.GetCciAdapter(), generation: 0));
Cci.MetadataWriter.GetMetadataName(type.GetCciAdapter(), generation: 0));

// First check against types declared in the primary module
if (ContainsTopLevelType(fullEmittedName))
Expand Down
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 @@ -2095,6 +2095,7 @@ internal enum ErrorCode
ERR_FileTypeDisallowedInSignature = 9300,
ERR_FileTypeNoExplicitAccessibility = 9301,
ERR_FileTypeBase = 9302,
ERR_FileTypeNested = 9303,

#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,11 @@ public override void VisitNamedType(INamedTypeSymbol symbol)
AddNullableAnnotations(symbol);

if ((format.CompilerInternalOptions & SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes) != 0
// PROTOTYPE(ft): public API?
&& symbol.GetSymbol() is SourceMemberContainerTypeSymbol { IsFile: true } fileType)
&& symbol is Symbols.PublicModel.Symbol { UnderlyingSymbol: SourceMemberContainerTypeSymbol { AssociatedSyntaxTree: SyntaxTree tree } internalSymbol })
{
var tree = symbol.DeclaringSyntaxReferences[0].SyntaxTree;
var fileDescription = tree.FilePath is { Length: not 0 } path
? Path.GetFileNameWithoutExtension(path)
: $"<tree {fileType.DeclaringCompilation.SyntaxTrees.IndexOf(tree)}>";
var fileDescription = tree.GetDisplayFileName() is { Length: not 0 } path
? path
: $"<tree {internalSymbol.DeclaringCompilation.SyntaxTrees.IndexOf(tree)}>";

builder.Add(CreatePart(SymbolDisplayPartKind.Punctuation, symbol, "@"));
builder.Add(CreatePart(SymbolDisplayPartKind.ModuleName, symbol, fileDescription));
Expand Down
4 changes: 3 additions & 1 deletion src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -479,16 +479,18 @@ public virtual bool IsImplicitClass
/// </summary>
public abstract override string Name { get; }

#nullable enable
/// <summary>
/// Return the name including the metadata arity suffix.
/// </summary>
public override string MetadataName
{
get
{
return MangleName ? MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity) : Name;
return MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity, this.AssociatedFileIdentifier());
}
}
#nullable disable

/// <summary>
/// Should the name returned by Name property be mangled with [`arity] suffix in order to get metadata name.
Expand Down
22 changes: 22 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/NamespaceOrTypeSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,28 @@ internal virtual NamedTypeSymbol LookupMetadataType(ref MetadataTypeName emitted
}
}

if (isTopLevel && MetadataHelpers.DecodeFileType(emittedTypeName.UnmangledTypeName) is (not -1 and var ordinal, var typeName))
{
// also do a lookup for file types from source.
namespaceOrTypeMembers = scope.GetTypeMembers(typeName);
foreach (var named in namespaceOrTypeMembers)
{
if (named is SourceMemberContainerTypeSymbol { AssociatedSyntaxTree: SyntaxTree tree }
&& named.DeclaringCompilation.GetSyntaxTreeOrdinal(tree) == ordinal
&& (emittedTypeName.ForcedArity == -1 || emittedTypeName.ForcedArity == emittedTypeName.InferredArity)
&& emittedTypeName.InferredArity == named.Arity)
{
if ((object?)namedType != null)
{
namedType = null;
break;
}

namedType = named;
}
}
}

Done:
if ((object?)namedType == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1743,6 +1743,11 @@ protected void AfterMembersChecks(BindingDiagnosticBag diagnostics)
}
}

if (IsFile && (object?)ContainingType != null)
{
diagnostics.Add(ErrorCode.ERR_FileTypeNested, location, this);
}

return;

bool hasBaseTypeOrInterface(Func<NamedTypeSymbol, bool> predicate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal enum GeneratedNameKind
ReusableHoistedLocalField = '7',
LambdaCacheField = '9',
FixedBufferField = 'e',
FileType = 'F',
AnonymousType = 'f',
TransparentIdentifier = 'h',
AnonymousTypeField = 'i',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -494,5 +494,38 @@ internal static string LambdaCopyParameterName(int ordinal)
{
return "<p" + StringExtensions.GetNumeral(ordinal) + ">";
}

internal static string MakeFileIdentifier(string filePath, int ordinal)
{
var pooledBuilder = PooledStringBuilder.GetInstance();
var sb = pooledBuilder.Builder;
sb.Append('<');
AppendFileName(filePath, sb);
sb.Append('>');
sb.Append((char)GeneratedNameKind.FileType);
sb.Append(ordinal);
sb.Append("__");
return pooledBuilder.ToStringAndFree();
}

internal static void AppendFileName(string? filePath, StringBuilder sb)
{
var fileName = FileNameUtilities.GetFileName(filePath, includeExtension: false);
if (fileName is null)
{
return;
}

foreach (var ch in fileName)
{
sb.Append(ch switch
{
>= 'a' and <= 'z' => ch,
>= 'A' and <= 'Z' => ch,
>= '0' and <= '9' => ch,
_ => '_'
});
}
}
}
}
19 changes: 19 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;

Expand Down Expand Up @@ -1361,6 +1362,24 @@ public static bool IsFileTypeOrUsesFileTypes(this TypeSymbol type)
return foundType is not null;
}

internal static string? AssociatedFileIdentifier(this NamedTypeSymbol type)
{
if (type is not SourceMemberContainerTypeSymbol { AssociatedSyntaxTree: SyntaxTree tree })
{
return null;
}
var ordinal = type.DeclaringCompilation.GetSyntaxTreeOrdinal(tree);
return GeneratedNames.MakeFileIdentifier(tree.FilePath, ordinal);
}

internal static string GetDisplayFileName(this SyntaxTree tree)
{
var pooledBuilder = PooledStringBuilder.GetInstance();
var sb = pooledBuilder.Builder;
GeneratedNames.AppendFileName(tree.FilePath, sb);
return pooledBuilder.ToStringAndFree();
}

public static bool IsPointerType(this TypeSymbol type)
{
return type is PointerTypeSymbol;
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf

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

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

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

Loading