Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -261,17 +261,29 @@ public bool Equals(MethodSymbol? x, MethodSymbol? y)
return false;
}

var xGroupingKey = new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(x.OriginalDefinition.ContainingType);
var yGroupingKey = new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(y.OriginalDefinition.ContainingType);
var xExtension = x.OriginalDefinition.ContainingType;
var xGroupingKey = ((SourceNamedTypeSymbol)xExtension).GetExtensionGroupingMetadataName();
var yExtension = y.OriginalDefinition.ContainingType;
var yGroupingKey = ((SourceNamedTypeSymbol)yExtension).GetExtensionGroupingMetadataName();

if (!xGroupingKey.Equals(yGroupingKey))
{
return false;
}

return SourceMemberContainerTypeSymbol.DoOperatorsPair(
x.OriginalDefinition.AsMember(xGroupingKey.NormalizedExtension),
y.OriginalDefinition.AsMember(yGroupingKey.NormalizedExtension));
x.OriginalDefinition.AsMember(Normalize(xExtension)),
y.OriginalDefinition.AsMember(Normalize(yExtension)));
}

private static NamedTypeSymbol Normalize(NamedTypeSymbol extension)
{
if (extension.Arity != 0)
{
extension = extension.Construct(IndexedTypeParameterSymbol.Take(extension.Arity));
}

return extension;
}

public int GetHashCode(MethodSymbol op)
Expand All @@ -280,10 +292,11 @@ public int GetHashCode(MethodSymbol op)

int result = typeComparer.GetHashCode(op.OriginalDefinition.ContainingType.ContainingType);

var groupingKey = new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(op.OriginalDefinition.ContainingType);
var extension = op.OriginalDefinition.ContainingType;
var groupingKey = ((SourceNamedTypeSymbol)extension).GetExtensionGroupingMetadataName();
result = Hash.Combine(result, groupingKey.GetHashCode());

foreach (var parameter in op.OriginalDefinition.AsMember(groupingKey.NormalizedExtension).Parameters)
foreach (var parameter in op.OriginalDefinition.AsMember(Normalize(extension)).Parameters)
{
result = Hash.Combine(result, typeComparer.GetHashCode(parameter.Type));
}
Expand Down
8 changes: 8 additions & 0 deletions src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,14 @@ private void CompileNamedType(NamedTypeSymbol containingType)
}

var members = containingType.GetMembers();

if (containingType.IsExtension && ((SourceNamedTypeSymbol)containingType).TryGetOrCreateExtensionMarker() is { } marker)
{
// The marker method is not among the members of the type, so we need to compile it separately.
Binder.ProcessedFieldInitializers processedInitializers = default;
CompileMethod(marker, -1, ref processedInitializers, synthesizedSubmissionFields, compilationState);
}

for (int memberOrdinal = 0; memberOrdinal < members.Length; memberOrdinal++)
{
var member = members[memberOrdinal];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ public override object VisitNamedType(NamedTypeSymbol symbol, StringBuilder buil
builder.Append('.');
}

// PROTOTYPE: Finalize the doc ID story. When we refer to a member, we probably need to use grouping type name,
// but when we refer to an extension block, we probably need to "dot" through both names.
builder.Append(symbol.IsExtension ? symbol.ExtensionName : symbol.Name);

if (symbol.Arity != 0)
Expand All @@ -189,8 +191,11 @@ public override object VisitNamedType(NamedTypeSymbol symbol, StringBuilder buil
// (and return type, for conversions) as constructed with its own type parameters.
if (!_inParameterOrReturnType && TypeSymbol.Equals(symbol, symbol.ConstructedFrom, TypeCompareKind.AllIgnoreOptions))
{
builder.Append('`');
builder.Append(symbol.Arity);
if (!symbol.IsExtension)
{
builder.Append('`');
builder.Append(symbol.Arity);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,7 @@ public override Cci.ISpecializedNestedTypeReference AsSpecializedNestedTypeRefer
{
get { return null; }
}

bool Cci.INestedTypeReference.InheritsEnclosingTypeTypeParameters => true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ Cci.ITypeReference Cci.ITypeMemberReference.GetContainingType(EmitContext contex
}

NamedTypeSymbol containingType = AdaptedMethodSymbol.ContainingType;

if (AdaptedMethodSymbol is SynthesizedExtensionMarker)
{
return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingMarkerType((SourceNamedTypeSymbol)containingType);
}
else if (AdaptedMethodSymbol.GetIsNewExtensionMember())
{
return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingGroupingType((SourceNamedTypeSymbol)containingType);
}

var moduleBeingBuilt = (PEModuleBuilder)context.Module;

return moduleBeingBuilt.Translate(containingType,
Expand Down Expand Up @@ -300,6 +310,18 @@ Cci.ITypeDefinition Cci.ITypeDefinitionMember.ContainingTypeDefinition
return synthesizedGlobalMethod.ContainingPrivateImplementationDetailsType;
}

// PROTOTYPE: Share logic with Cci.ITypeMemberReference.GetContainingType implementation?
if (AdaptedMethodSymbol is SynthesizedExtensionMarker)
{
var containingType = AdaptedMethodSymbol.ContainingType;
return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingMarkerType((SourceNamedTypeSymbol)containingType);
}
else if (AdaptedMethodSymbol.GetIsNewExtensionMember())
{
var containingType = AdaptedMethodSymbol.ContainingType;
return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingGroupingType((SourceNamedTypeSymbol)containingType);
}

return AdaptedMethodSymbol.ContainingType.GetCciAdapter();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ Cci.INestedTypeReference Cci.ITypeReference.AsNestedTypeReference
}
}

bool Cci.INestedTypeReference.InheritsEnclosingTypeTypeParameters => true;

Cci.INestedTypeDefinition Cci.ITypeReference.AsNestedTypeDefinition(EmitContext context)
{
PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
Expand Down Expand Up @@ -629,7 +631,7 @@ bool Cci.ITypeDefinition.IsSealed
{
Debug.Assert((object)method != null);

if ((alwaysIncludeConstructors && method.MethodKind == MethodKind.Constructor) || method is SynthesizedExtensionMarker || method.GetCciAdapter().ShouldInclude(context))
if ((alwaysIncludeConstructors && method.MethodKind == MethodKind.Constructor) || method.GetCciAdapter().ShouldInclude(context))
{
yield return method.GetCciAdapter();
}
Expand All @@ -655,9 +657,22 @@ bool Cci.ITypeDefinition.IsSealed

foreach (NamedTypeSymbol type in AdaptedNamedTypeSymbol.GetTypeMembers()) // Ordered.
{
if (type.IsExtension)
{
continue;
}

yield return type.GetCciAdapter();
}

if (AdaptedNamedTypeSymbol is SourceMemberContainerTypeSymbol { MergedDeclaration.ContainsExtensionDeclarations: true } container)
{
foreach (var groupingType in container.GetExtensionGroupingInfo().GetGroupingTypes())
{
yield return groupingType;
}
}

IEnumerable<Cci.INestedTypeDefinition> generated = ((PEModuleBuilder)context.Module).GetSynthesizedTypes(AdaptedNamedTypeSymbol);

if (generated != null)
Expand Down Expand Up @@ -782,7 +797,7 @@ string Cci.INamedEntity.Name
{
if (AdaptedNamedTypeSymbol.IsExtension)
{
return AdaptedNamedTypeSymbol.ExtensionName;
throw ExceptionUtilities.Unreachable();
}

string unsuffixedName = AdaptedNamedTypeSymbol.Name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ internal abstract class PEAssemblyBuilderBase : PEModuleBuilder, Cci.IAssemblyRe
private SynthesizedEmbeddedNativeIntegerAttributeSymbol _lazyNativeIntegerAttribute;
private SynthesizedEmbeddedScopedRefAttributeSymbol _lazyScopedRefAttribute;
private SynthesizedEmbeddedRefSafetyRulesAttributeSymbol _lazyRefSafetyRulesAttribute;
private SynthesizedEmbeddedExtensionMarkerNameAttributeSymbol _lazyExtensionMarkerNameAttribute;

/// <summary>
/// The behavior of the C# command-line compiler is as follows:
Expand Down Expand Up @@ -111,6 +112,7 @@ internal sealed override ImmutableArray<NamedTypeSymbol> GetEmbeddedTypes(Bindin
builder.AddIfNotNull(_lazyNativeIntegerAttribute);
builder.AddIfNotNull(_lazyScopedRefAttribute);
builder.AddIfNotNull(_lazyRefSafetyRulesAttribute);
builder.AddIfNotNull(_lazyExtensionMarkerNameAttribute);

return builder.ToImmutableAndFree();
}
Expand Down Expand Up @@ -337,6 +339,25 @@ protected override SynthesizedAttributeData TrySynthesizeParamCollectionAttribut
return base.TrySynthesizeParamCollectionAttribute();
}

protected override SynthesizedAttributeData TrySynthesizeExtensionMarkerNameAttribute(string markerName)
{
if ((object)_lazyExtensionMarkerNameAttribute != null)
{
return SynthesizedAttributeData.Create(
Compilation,
_lazyExtensionMarkerNameAttribute.Constructors[0],
[new TypedConstant(Compilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, markerName)],
ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty);
}

return base.TrySynthesizeExtensionMarkerNameAttribute(markerName);
}

internal override SynthesizedEmbeddedAttributeSymbol TryGetSynthesizedIsUnmanagedAttribute()
{
return _lazyIsUnmanagedAttribute;
}

protected override SynthesizedAttributeData TrySynthesizeIsUnmanagedAttribute()
{
if ((object)_lazyIsUnmanagedAttribute != null)
Expand Down Expand Up @@ -494,6 +515,15 @@ private void CreateEmbeddedAttributesIfNeeded(BindingDiagnosticBag diagnostics)
AttributeDescription.RefSafetyRulesAttribute,
CreateRefSafetyRulesAttributeSymbol);
}

if ((needsAttributes & EmbeddableAttributes.ExtensionMarkerNameAttribute) != 0)
{
CreateAttributeIfNeeded(
ref _lazyExtensionMarkerNameAttribute,
diagnostics,
AttributeDescription.ExtensionMarkerNameAttribute,
CreateExtensionMarkerNameAttributeSymbol);
}
}

private SynthesizedEmbeddedAttributeSymbol CreateParameterlessEmbeddedAttributeSymbol(string name, NamespaceSymbol containingNamespace, BindingDiagnosticBag diagnostics)
Expand Down Expand Up @@ -550,6 +580,14 @@ private SynthesizedEmbeddedRefSafetyRulesAttributeSymbol CreateRefSafetyRulesAtt
GetWellKnownType(WellKnownType.System_Attribute, diagnostics),
GetSpecialType(SpecialType.System_Int32, diagnostics));

private SynthesizedEmbeddedExtensionMarkerNameAttributeSymbol CreateExtensionMarkerNameAttributeSymbol(string name, NamespaceSymbol containingNamespace, BindingDiagnosticBag diagnostics)
=> new SynthesizedEmbeddedExtensionMarkerNameAttributeSymbol(
name,
containingNamespace,
SourceModule,
GetWellKnownType(WellKnownType.System_Attribute, diagnostics),
GetSpecialType(SpecialType.System_String, diagnostics));

#nullable enable
private void CreateAttributeIfNeeded<T>(
ref T symbol,
Expand Down
29 changes: 28 additions & 1 deletion src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,10 @@ private static void GetDocumentsForMethodsAndNestedTypes(PooledHashSet<Cci.Debug
switch (member.Kind)
{
case SymbolKind.NamedType:
namespacesAndTypesToProcess.Push((NamespaceOrTypeSymbol)member);
if (!((NamedTypeSymbol)member).IsExtension) // PROTOTYPE: Figure out what to do about extensions, if anything
{
namespacesAndTypesToProcess.Push((NamespaceOrTypeSymbol)member);
}
break;

case SymbolKind.Method:
Expand Down Expand Up @@ -1522,6 +1525,17 @@ internal SynthesizedAttributeData SynthesizeParamCollectionAttribute(ParameterSy
return TrySynthesizeParamCollectionAttribute();
}

internal SynthesizedAttributeData SynthesizeExtensionMarkerNameAttribute(Symbol symbol, string markerName)
{
if ((object)Compilation.SourceModule != symbol.ContainingModule)
{
// For symbols that are not defined in the same compilation (like NoPia), don't synthesize this attribute.
return null;
}

return TrySynthesizeExtensionMarkerNameAttribute(markerName);
}

internal SynthesizedAttributeData SynthesizeIsUnmanagedAttribute(Symbol symbol)
{
if ((object)Compilation.SourceModule != symbol.ContainingModule)
Expand Down Expand Up @@ -1740,6 +1754,19 @@ protected virtual SynthesizedAttributeData TrySynthesizeParamCollectionAttribute
return Compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_ParamCollectionAttribute__ctor);
}

protected virtual SynthesizedAttributeData TrySynthesizeExtensionMarkerNameAttribute(string markerName)
{
// For modules, this attribute should be present. Only assemblies generate and embed this type.
return Compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_ExtensionMarkerNameAttribute__ctor,
[new TypedConstant(Compilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, markerName)]);
}

internal virtual SynthesizedEmbeddedAttributeSymbol TryGetSynthesizedIsUnmanagedAttribute()
{
// For modules, this attribute should be present. Only assemblies generate and embed this type.
return null;
}

protected virtual SynthesizedAttributeData TrySynthesizeIsUnmanagedAttribute()
{
// For modules, this attribute should be present. Only assemblies generate and embed this type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ ITypeDefinition ITypeDefinitionMember.ContainingTypeDefinition
get
{
CheckDefinitionInvariant();

// PROTOTYPE: Share logic with Cci.ITypeMemberReference.GetContainingType implementation?
if (AdaptedPropertySymbol.GetIsNewExtensionMember())
{
var containingType = AdaptedPropertySymbol.ContainingType;
return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingGroupingType((SourceNamedTypeSymbol)containingType);
}

return AdaptedPropertySymbol.ContainingType.GetCciAdapter();
}
}
Expand All @@ -240,6 +248,14 @@ TypeMemberVisibility ITypeDefinitionMember.Visibility
ITypeReference ITypeMemberReference.GetContainingType(EmitContext context)
{
CheckDefinitionInvariant();

// PROTOTYPE: Share logic with Cci.ITypeMemberReference.GetContainingType implementation in MethodSymbolAdapter?
if (AdaptedPropertySymbol.GetIsNewExtensionMember())
{
var containingType = AdaptedPropertySymbol.ContainingType;
return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingGroupingType((SourceNamedTypeSymbol)containingType);
}

return AdaptedPropertySymbol.ContainingType.GetCciAdapter();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,7 @@ public override Cci.ISpecializedNestedTypeReference AsSpecializedNestedTypeRefer
{
get { return this; }
}

bool Cci.INestedTypeReference.InheritsEnclosingTypeTypeParameters => true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ private void AddNameAndTypeArgumentsOrParameters(INamedTypeSymbol symbol)
{
if (Format.CompilerInternalOptions.HasFlag(SymbolDisplayCompilerInternalOptions.UseMetadataMemberNames))
{
// PROTOTYPE: What should we output as the name here
var extensionIdentifier = underlyingTypeSymbol!.ExtensionName; // Tracked by https://github.com/dotnet/roslyn/issues/78957 : public API, use public API once it's available
Builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, extensionIdentifier));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,11 @@ internal void EnsureScopedRefAttributeExists(BindingDiagnosticBag? diagnostics,
EnsureEmbeddableAttributeExists(EmbeddableAttributes.ScopedRefAttribute, diagnostics, location, modifyCompilation);
}

internal void EnsureExtensionMarkerNameAttributeExists(BindingDiagnosticBag? diagnostics, Location location, bool modifyCompilation)
{
EnsureEmbeddableAttributeExists(EmbeddableAttributes.ExtensionMarkerNameAttribute, diagnostics, location, modifyCompilation);
}

internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, BindingDiagnosticBag? diagnosticsOpt, Location locationOpt)
{
switch (attribute)
Expand Down Expand Up @@ -659,6 +664,13 @@ internal bool CheckIfAttributeShouldBeEmbedded(EmbeddableAttributes attribute, B
WellKnownType.System_Runtime_CompilerServices_ParamCollectionAttribute,
WellKnownMember.System_Runtime_CompilerServices_ParamCollectionAttribute__ctor);

case EmbeddableAttributes.ExtensionMarkerNameAttribute:
return CheckIfAttributeShouldBeEmbedded(
diagnosticsOpt,
locationOpt,
WellKnownType.System_Runtime_CompilerServices_ExtensionMarkerNameAttribute,
WellKnownMember.System_Runtime_CompilerServices_ExtensionMarkerNameAttribute__ctor);

default:
throw ExceptionUtilities.UnexpectedValue(attribute);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ internal enum EmbeddableAttributes
RefSafetyRulesAttribute = 0x100,
RequiresLocationAttribute = 0x200,
ParamCollectionAttribute = 0x400,
ExtensionMarkerNameAttribute = 0x800,
}
}
Loading