Skip to content

Commit

Permalink
Merge pull request #44078 from 333fred/transforms-2
Browse files Browse the repository at this point in the history
dynamic and nint decoding support
  • Loading branch information
333fred committed May 14, 2020
2 parents eb2e920 + d809b3a commit c9e80fe
Show file tree
Hide file tree
Showing 12 changed files with 731 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,21 @@ public override void VisitMethod(IMethodSymbol symbol)
AddSpace();
}

if (symbol.ReturnsByRef)
{
AddRefIfRequired();
}
else if (symbol.ReturnsByRefReadonly)
{
AddRefReadonlyIfRequired();
}

AddCustomModifiersIfRequired(symbol.RefCustomModifiers);

symbol.ReturnType.Accept(this.NotFirstVisitor);

AddCustomModifiersIfRequired(symbol.ReturnTypeCustomModifiers, leadingSpace: true, trailingSpace: false);

AddPunctuation(SyntaxKind.GreaterThanToken);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,7 @@ internal static void Encode(TypeSymbol type, int customModifiersCount, RefKind r

private static bool AddFlags(TypeSymbol type, ArrayBuilder<bool> transformFlagsBuilder, bool isNestedNamedType, bool addCustomModifierFlags)
{
// Encode transforms flag for this type and it's custom modifiers (if any).
// Encode transforms flag for this type and its custom modifiers (if any).
switch (type.TypeKind)
{
case TypeKind.Dynamic:
Expand All @@ -887,6 +887,16 @@ private static bool AddFlags(TypeSymbol type, ArrayBuilder<bool> transformFlagsB
transformFlagsBuilder.Add(false);
break;

case TypeKind.FunctionPointer:
Debug.Assert(!isNestedNamedType);
handleFunctionPointerType((FunctionPointerTypeSymbol)type, transformFlagsBuilder, addCustomModifierFlags);

// Function pointer types have nested custom modifiers and refkinds in line with types, and visit all their nested types
// as part of this call.
// We need a different way to indicate that we should not recurse for this type, but should continue walking for other
// types. https://github.com/dotnet/roslyn/issues/44160
return true;

default:
// Encode transforms flag for this type.
// For nested named types, a single flag (false) is encoded for the entire type name, followed by flags for all of the type arguments.
Expand All @@ -906,6 +916,43 @@ private static bool AddFlags(TypeSymbol type, ArrayBuilder<bool> transformFlagsB

// Continue walking types
return false;

static void handleFunctionPointerType(FunctionPointerTypeSymbol funcPtr, ArrayBuilder<bool> transformFlagsBuilder, bool addCustomModifierFlags)
{
Func<TypeSymbol, (ArrayBuilder<bool>, bool), bool, bool> visitor =
(TypeSymbol type, (ArrayBuilder<bool> builder, bool addCustomModiferFlags) param, bool isNestedNamedType) => AddFlags(type, param.builder, isNestedNamedType, param.addCustomModiferFlags);

// The function pointer type itself gets a false
transformFlagsBuilder.Add(false);

var sig = funcPtr.Signature;
handle(sig.RefKind, sig.RefCustomModifiers, sig.ReturnTypeWithAnnotations);

foreach (var param in sig.Parameters)
{
handle(param.RefKind, param.RefCustomModifiers, param.TypeWithAnnotations);
}

void handle(RefKind refKind, ImmutableArray<CustomModifier> customModifiers, TypeWithAnnotations twa)
{
if (addCustomModifierFlags)
{
HandleCustomModifiers(customModifiers.Length, transformFlagsBuilder);
}

if (refKind != RefKind.None)
{
transformFlagsBuilder.Add(false);
}

if (addCustomModifierFlags)
{
HandleCustomModifiers(twa.CustomModifiers.Length, transformFlagsBuilder);
}

twa.Type.VisitType(visitor, (transformFlagsBuilder, addCustomModifierFlags));
}
}
}

private static void HandleCustomModifiers(int customModifiersCount, ArrayBuilder<bool> transformFlagsBuilder)
Expand Down Expand Up @@ -935,6 +982,7 @@ private static bool AddFlags(TypeSymbol type, ArrayBuilder<bool> builder, bool i
{
case TypeKind.Array:
case TypeKind.Pointer:
case TypeKind.FunctionPointer:
case TypeKind.TypeParameter:
case TypeKind.Dynamic:
builder.Add(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ public static int CustomModifierCount(this Symbol m)
case SymbolKind.NamedType:
case SymbolKind.PointerType:
case SymbolKind.TypeParameter:
case SymbolKind.FunctionPointer:
return ((TypeSymbol)m).CustomModifierCount();
case SymbolKind.Event:
return ((EventSymbol)m).CustomModifierCount();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private static TypeSymbol TransformTypeInternal(
var decoder = new DynamicTypeDecoder(dynamicTransformFlags, haveCustomModifierFlags, checkLength, containingAssembly);

// Native compiler encodes bools (always false) for custom modifiers and parameter ref-kinds, if ref-kind is ref or out.
if (decoder.HandleCustomModifiers(targetSymbolCustomModifierCount) && decoder.HandleParameterRefKind(targetSymbolRefKind))
if (decoder.HandleCustomModifiers(targetSymbolCustomModifierCount) && decoder.HandleRefKind(targetSymbolRefKind))
{
TypeSymbol transformedType = decoder.TransformType(metadataType);

Expand Down Expand Up @@ -164,6 +164,9 @@ private TypeSymbol TransformType(TypeSymbol type)
case SymbolKind.PointerType:
return TransformPointerType((PointerTypeSymbol)type);

case SymbolKind.FunctionPointer:
return TransformFunctionPointerType((FunctionPointerTypeSymbol)type);

case SymbolKind.DynamicType:
Debug.Assert(!_haveCustomModifierFlags, "This shouldn't happen during decoding.");
return ConsumeFlag()
Expand Down Expand Up @@ -200,8 +203,8 @@ private bool HandleCustomModifiers(int customModifiersCount)
return true;
}

// Native compiler encodes bools (always false) for custom modifiers and parameter ref-kinds, if ref-kind is ref or out.
private bool HandleParameterRefKind(RefKind refKind)
// Native compiler encodes bools (always false) for custom modifiers and parameter ref-kinds, if ref-kind is not none.
private bool HandleRefKind(RefKind refKind)
{
Debug.Assert(_index >= 0);
return refKind == RefKind.None || !ConsumeFlag();
Expand Down Expand Up @@ -338,6 +341,83 @@ private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType)
new PointerTypeSymbol(pointerType.PointedAtTypeWithAnnotations.WithTypeAndModifiers(transformedPointedAtType, pointerType.PointedAtTypeWithAnnotations.CustomModifiers));
}

#nullable enable
private FunctionPointerTypeSymbol? TransformFunctionPointerType(FunctionPointerTypeSymbol type)
{
var flag = ConsumeFlag();
Debug.Assert(!flag);

var sig = type.Signature;

var (transformedReturnWithAnnotations, madeChanges) = handle(ref this, sig.RefKind, sig.RefCustomModifiers, sig.ReturnTypeWithAnnotations);
if (transformedReturnWithAnnotations.IsDefault)
{
return null;
}

var transformedParameters = ImmutableArray<TypeWithAnnotations>.Empty;
if (sig.ParameterCount > 0)
{
var paramsTransformed = false;
var paramsBuilder = ArrayBuilder<TypeWithAnnotations>.GetInstance(sig.ParameterCount);
try
{
foreach (var param in sig.Parameters)
{
var (transformedParamType, paramTransformed) = handle(ref this, param.RefKind, param.RefCustomModifiers, param.TypeWithAnnotations);
if (transformedParamType.IsDefault)
{
return null;
}

paramsBuilder.Add(transformedParamType);
paramsTransformed |= paramTransformed;
}

transformedParameters = paramsTransformed ? paramsBuilder.ToImmutable() : sig.ParameterTypesWithAnnotations;
madeChanges |= paramsTransformed;
}
finally
{
paramsBuilder.Free();
}
}

if (madeChanges)
{
return type.SubstituteTypeSymbol(transformedReturnWithAnnotations, transformedParameters,
refCustomModifiers: default, paramRefCustomModifiers: default);
}
else
{
return type;
}

static (TypeWithAnnotations, bool madeChanges) handle(ref DynamicTypeDecoder decoder, RefKind refKind, ImmutableArray<CustomModifier> refCustomModifiers, TypeWithAnnotations typeWithAnnotations)
{
if (!decoder.HandleCustomModifiers(refCustomModifiers.Length)
|| !decoder.HandleRefKind(refKind)
|| !decoder.HandleCustomModifiers(typeWithAnnotations.CustomModifiers.Length))
{
return (default, false);
}

var transformedType = decoder.TransformType(typeWithAnnotations.Type);
if (transformedType is null)
{
return (default, false);
}

if (transformedType.Equals(typeWithAnnotations.Type, TypeCompareKind.ConsiderEverything))
{
return (typeWithAnnotations, false);
}

return (typeWithAnnotations.WithType(transformedType), true);
}
}
#nullable restore

private bool HasFlag => _index < _dynamicTransformFlags.Length || !_checkLength;

private bool PeekFlag() => _index < _dynamicTransformFlags.Length && _dynamicTransformFlags[_index];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ private TypeSymbol TransformType(TypeSymbol type)
return TransformArrayType((ArrayTypeSymbol)type);
case TypeKind.Pointer:
return TransformPointerType((PointerTypeSymbol)type);
case TypeKind.FunctionPointer:
return TransformFunctionPointerType((FunctionPointerTypeSymbol)type);
case TypeKind.TypeParameter:
case TypeKind.Dynamic:
IgnoreIndex();
Expand Down Expand Up @@ -137,6 +139,45 @@ private PointerTypeSymbol TransformPointerType(PointerTypeSymbol type)
return type.WithPointedAtType(TransformTypeWithAnnotations(type.PointedAtTypeWithAnnotations));
}

private FunctionPointerTypeSymbol TransformFunctionPointerType(FunctionPointerTypeSymbol type)
{
IgnoreIndex();

var transformedReturnType = TransformTypeWithAnnotations(type.Signature.ReturnTypeWithAnnotations);
var transformedParameterTypes = ImmutableArray<TypeWithAnnotations>.Empty;
var paramsModified = false;

if (type.Signature.ParameterCount > 0)
{
var builder = ArrayBuilder<TypeWithAnnotations>.GetInstance(type.Signature.ParameterCount);
foreach (var param in type.Signature.Parameters)
{
var transformedParam = TransformTypeWithAnnotations(param.TypeWithAnnotations);
paramsModified = paramsModified || !transformedParam.IsSameAs(param.TypeWithAnnotations);
builder.Add(transformedParam);
}

if (paramsModified)
{
transformedParameterTypes = builder.ToImmutableAndFree();
}
else
{
transformedParameterTypes = type.Signature.ParameterTypesWithAnnotations;
builder.Free();
}
}

if (paramsModified || !transformedReturnType.IsSameAs(type.Signature.ReturnTypeWithAnnotations))
{
return type.SubstituteTypeSymbol(transformedReturnType, transformedParameterTypes, refCustomModifiers: default, paramRefCustomModifiers: default);
}
else
{
return type;
}
}

private int Increment()
{
if (_index < _transformFlags.Length)
Expand Down
28 changes: 16 additions & 12 deletions src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -696,33 +696,37 @@ private static bool IsTypeLessVisibleThan(TypeSymbol type, Symbol sym, ref HashS

static TypeSymbol? visitFunctionPointerType(FunctionPointerTypeSymbol type, Func<TypeWithAnnotations, T, bool, bool>? typeWithAnnotationsPredicate, Func<TypeSymbol, T, bool, bool>? typePredicate, T arg, bool useDefaultType, bool canDigThroughNullable)
{

MethodSymbol currentPointer = type.Signature;
var result = visitType(currentPointer.ReturnTypeWithAnnotations);
var result = VisitType(
typeWithAnnotationsOpt: canDigThroughNullable ? default : currentPointer.ReturnTypeWithAnnotations,
type: canDigThroughNullable ? currentPointer.ReturnTypeWithAnnotations.NullableUnderlyingTypeOrSelf : null,
typeWithAnnotationsPredicate,
typePredicate,
arg,
canDigThroughNullable,
useDefaultType);
if (result is object)
{
return result;
}

foreach (var parameter in currentPointer.Parameters)
{
result = visitType(parameter.TypeWithAnnotations);
result = VisitType(
typeWithAnnotationsOpt: canDigThroughNullable ? default : parameter.TypeWithAnnotations,
type: canDigThroughNullable ? parameter.TypeWithAnnotations.NullableUnderlyingTypeOrSelf : null,
typeWithAnnotationsPredicate,
typePredicate,
arg,
canDigThroughNullable,
useDefaultType);
if (result is object)
{
return result;
}
}

return null;

TypeSymbol? visitType(TypeWithAnnotations typeArg) => VisitType(
typeWithAnnotationsOpt: canDigThroughNullable ? default : typeArg,
type: canDigThroughNullable ? typeArg.NullableUnderlyingTypeOrSelf : null,
typeWithAnnotationsPredicate,
typePredicate,
arg,
canDigThroughNullable,
useDefaultType);
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,9 @@ public bool Is(TypeParameterSymbol other)
public TypeWithAnnotations WithTypeAndModifiers(TypeSymbol typeSymbol, ImmutableArray<CustomModifier> customModifiers) =>
_extensions.WithTypeAndModifiers(this, typeSymbol, customModifiers);

public TypeWithAnnotations WithType(TypeSymbol typeSymbol) =>
_extensions.WithTypeAndModifiers(this, typeSymbol, CustomModifiers);

/// <summary>
/// Used by callers before calling CSharpCompilation.EnsureNullableAttributeExists().
/// </summary>
Expand Down
Loading

0 comments on commit c9e80fe

Please sign in to comment.