Skip to content

Commit

Permalink
Merge pull request #57135 from RikkiGibson/delegate-type-args
Browse files Browse the repository at this point in the history
Support 'ref' type arguments in delegates
  • Loading branch information
RikkiGibson committed Oct 14, 2021
2 parents 9652b5c + f3dbce9 commit 5593bc8
Show file tree
Hide file tree
Showing 17 changed files with 635 additions and 4 deletions.
50 changes: 48 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,10 +474,18 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS
var refToken = refTypeSyntax.RefKeyword;
if (!syntax.HasErrors)
{
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, refToken.GetLocation(), refToken.ToString());
// PROTOTYPE(delegate-type-args): restore this diagnostic in non-delegate call sites
// diagnostics.Add(ErrorCode.ERR_UnexpectedToken, refToken.GetLocation(), refToken.ToString());
}

return BindNamespaceOrTypeOrAliasSymbol(refTypeSyntax.Type, diagnostics, basesBeingResolved, suppressUseSiteDiagnostics);
var referencedType = BindNamespaceOrTypeOrAliasSymbol(refTypeSyntax.Type, diagnostics, basesBeingResolved, suppressUseSiteDiagnostics);
if (referencedType.IsType)
{
return TypeWithAnnotations.Create(new RefTypeSymbol(RefKind.Ref, referencedType.TypeWithAnnotations));
}

// PROTOTYPE(delegate-type-args): handle aliases
return createErrorType();
}

default:
Expand Down Expand Up @@ -1171,6 +1179,20 @@ private TypeWithAnnotations BindGenericSimpleNamespaceOrTypeOrAliasSymbol(
{
resultType = unconstructedType.Construct(PlaceholderTypeArgumentSymbol.CreateTypeArguments(unconstructedType.TypeParameters));
}
else if (unconstructedType.IsDelegateType())
{
var types = BindDelegateTypeArguments(typeArguments, diagnostics, basesBeingResolved);
// PROTOTYPE(delegate-type-args): assert that if we are looking up an attribute, there must be other errors
// PROTOTYPE(delegate-type-args): check validity of ref kinds etc in delegate signature
resultType = unconstructedType.Construct(types);
if (ShouldCheckConstraints && ConstraintsHelper.RequiresChecking(resultType))
{
bool includeNullability = Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
resultType.CheckConstraintsForNamedType(new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability, node.Location, diagnostics),
node, typeArguments, basesBeingResolved);
}

}
else
{
var boundTypeArguments = BindTypeArguments(typeArguments, diagnostics, basesBeingResolved);
Expand Down Expand Up @@ -1284,6 +1306,30 @@ private ExtendedErrorTypeSymbol CreateErrorIfLookupOnTypeParameter(
return null;
}

private ImmutableArray<TypeWithAnnotations> BindDelegateTypeArguments(SeparatedSyntaxList<TypeSyntax> typeArguments, BindingDiagnosticBag diagnostics, ConsList<TypeSymbol> basesBeingResolved = null)
{
Debug.Assert(typeArguments.Count > 0);
var types = ArrayBuilder<TypeWithAnnotations>.GetInstance();
foreach (var argSyntax in typeArguments)
{
var type = BindDelegateTypeArgument(argSyntax, diagnostics, basesBeingResolved);
types.Add(type);
}

return types.ToImmutableAndFree();
}

private TypeWithAnnotations BindDelegateTypeArgument(TypeSyntax typeArgument, BindingDiagnosticBag diagnostics, ConsList<TypeSymbol> basesBeingResolved = null)
{
var binder = this.WithAdditionalFlags(BinderFlags.SuppressUnsafeDiagnostics);

var symbol = BindTypeOrAlias(typeArgument, diagnostics, basesBeingResolved);
var alias = UnwrapAlias(symbol, diagnostics, typeArgument, basesBeingResolved).TypeWithAnnotations;

// PROTOTYPE: we should allow pointers, ref etc in this code path while continuing to disallow in the regular 'BindTypeArgument'
return alias;
}

private ImmutableArray<TypeWithAnnotations> BindTypeArguments(SeparatedSyntaxList<TypeSyntax> typeArguments, BindingDiagnosticBag diagnostics, ConsList<TypeSymbol> basesBeingResolved = null)
{
Debug.Assert(typeArguments.Count > 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,9 @@ internal sealed override Cci.ITypeReference Translate(

case SymbolKind.FunctionPointerType:
return Translate((FunctionPointerTypeSymbol)typeSymbol);

case SymbolKind.RefType:
return Translate((RefTypeSymbol)typeSymbol);
}

throw ExceptionUtilities.UnexpectedValue(typeSymbol.Kind);
Expand Down Expand Up @@ -1502,6 +1505,11 @@ internal Cci.IPointerTypeReference Translate(PointerTypeSymbol symbol)
return (Cci.IPointerTypeReference)GetCciAdapter(symbol);
}

internal Cci.IRefTypeReference Translate(RefTypeSymbol symbol)
{
return (Cci.IRefTypeReference)GetCciAdapter(symbol);
}

internal Cci.IFunctionPointerTypeReference Translate(FunctionPointerTypeSymbol symbol)
{
return (Cci.IFunctionPointerTypeReference)GetCciAdapter(symbol);
Expand Down
157 changes: 157 additions & 0 deletions src/Compilers/CSharp/Portable/Emitter/Model/RefTypeSymbolAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System.Collections.Immutable;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.Emit;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal partial class
#if DEBUG
RefTypeSymbolAdapter : SymbolAdapter,
#else
RefTypeSymbol :
#endif
Cci.IRefTypeReference
{
Cci.ITypeReference Cci.IRefTypeReference.GetReferencedType(EmitContext context)
{
var type = ((PEModuleBuilder)context.Module).Translate(AdaptedRefTypeSymbol.ReferencedTypeWithAnnotations.Type, syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode, diagnostics: context.Diagnostics);

if (AdaptedRefTypeSymbol.ReferencedTypeWithAnnotations.CustomModifiers.Length == 0)
{
return type;
}
else
{
return new Cci.ModifiedTypeReference(type, ImmutableArray<Cci.ICustomModifier>.CastUp(AdaptedRefTypeSymbol.ReferencedTypeWithAnnotations.CustomModifiers));
}
}

bool Cci.ITypeReference.IsEnum
{
get { return false; }
}

bool Cci.ITypeReference.IsValueType
{
get { return false; }
}

Cci.ITypeDefinition Cci.ITypeReference.GetResolvedType(EmitContext context)
{
return null;
}

Cci.PrimitiveTypeCode Cci.ITypeReference.TypeCode
{
get { return Cci.PrimitiveTypeCode.Reference; }
}

TypeDefinitionHandle Cci.ITypeReference.TypeDef
{
get { return default(TypeDefinitionHandle); }
}

Cci.IGenericMethodParameterReference Cci.ITypeReference.AsGenericMethodParameterReference
{
get { return null; }
}

Cci.IGenericTypeInstanceReference Cci.ITypeReference.AsGenericTypeInstanceReference
{
get { return null; }
}

Cci.IGenericTypeParameterReference Cci.ITypeReference.AsGenericTypeParameterReference
{
get { return null; }
}

Cci.INamespaceTypeDefinition Cci.ITypeReference.AsNamespaceTypeDefinition(EmitContext context)
{
return null;
}

Cci.INamespaceTypeReference Cci.ITypeReference.AsNamespaceTypeReference
{
get { return null; }
}

Cci.INestedTypeDefinition Cci.ITypeReference.AsNestedTypeDefinition(EmitContext context)
{
return null;
}

Cci.INestedTypeReference Cci.ITypeReference.AsNestedTypeReference
{
get { return null; }
}

Cci.ISpecializedNestedTypeReference Cci.ITypeReference.AsSpecializedNestedTypeReference
{
get { return null; }
}

Cci.ITypeDefinition Cci.ITypeReference.AsTypeDefinition(EmitContext context)
{
return null;
}

void Cci.IReference.Dispatch(Cci.MetadataVisitor visitor)
{
visitor.Visit((Cci.IPointerTypeReference)this);
}

Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context)
{
return null;
}
}

internal partial class RefTypeSymbol
{

#if DEBUG
private RefTypeSymbolAdapter _lazyAdapter;

protected sealed override SymbolAdapter GetCciAdapterImpl() => GetCciAdapter();

internal new RefTypeSymbolAdapter GetCciAdapter()
{
if (_lazyAdapter is null)
{
return InterlockedOperations.Initialize(ref _lazyAdapter, new RefTypeSymbolAdapter(this));
}

return _lazyAdapter;
}
#else
internal RefTypeSymbol AdaptedRefTypeSymbol => this;

internal new RefTypeSymbol GetCciAdapter()
{
return this;
}
#endif
}

#if DEBUG
internal partial class RefTypeSymbolAdapter
{
internal RefTypeSymbolAdapter(RefTypeSymbol underlyingRefTypeSymbol)
{
AdaptedRefTypeSymbol = underlyingRefTypeSymbol;
}

internal sealed override Symbol AdaptedSymbol => AdaptedRefTypeSymbol;
internal RefTypeSymbol AdaptedRefTypeSymbol { get; }
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

namespace Microsoft.CodeAnalysis.CSharp
{
// PROTOTYPE(delegate-type-args): symbol display
internal partial class SymbolDisplayVisitor
{
public override void VisitArrayType(IArrayTypeSymbol symbol)
Expand Down
34 changes: 34 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/PublicModel/RefTypeSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel
{
// PROTOTYPE(delegate-type-arg): public model?
// internal sealed class RefTypeSymbol : TypeSymbol
// {
// private readonly Symbols.RefTypeSymbol _underlying;

// internal override Symbols.TypeSymbol UnderlyingTypeSymbol => _underlying;
// internal override Symbols.NamespaceOrTypeSymbol UnderlyingNamespaceOrTypeSymbol => _underlying;
// internal override CSharp.Symbol UnderlyingSymbol => _underlying;

// protected override void Accept(SymbolVisitor visitor)
// {
// _underlying.ReferencedTypeWithAnnotations.Accept
// }

// protected override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
// {
// throw new System.NotImplementedException();
// }

// protected override ITypeSymbol WithNullableAnnotation(CodeAnalysis.NullableAnnotation nullableAnnotation)
// {
// throw new System.NotImplementedException();
// }
// }
}
Loading

0 comments on commit 5593bc8

Please sign in to comment.