Skip to content

Commit

Permalink
Merge pull request dotnet#48185 from dotnet/merges/release/dev16.8-to…
Browse files Browse the repository at this point in the history
…-release/dev16.8-vs-deps

Merge release/dev16.8 to release/dev16.8-vs-deps
  • Loading branch information
msftbot[bot] authored Sep 30, 2020
2 parents d0a23d1 + 1c155c5 commit 0d0ca13
Show file tree
Hide file tree
Showing 6 changed files with 425 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,7 @@ private Conversion ClassifyExplicitOnlyConversionFromExpression(BoundExpression
return GetExplicitUserDefinedConversion(sourceExpression, sourceType, destination, ref useSiteDiagnostics);
}

#nullable enable
private static bool HasImplicitEnumerationConversion(BoundExpression source, TypeSymbol destination)
{
Debug.Assert((object)source != null);
Expand All @@ -1239,9 +1240,11 @@ private static bool HasImplicitEnumerationConversion(BoundExpression source, Typ

var sourceConstantValue = source.ConstantValue;
return sourceConstantValue != null &&
IsNumericType(source.Type.GetSpecialTypeSafe()) &&
source.Type is object &&
IsNumericType(source.Type) &&
IsConstantNumericZero(sourceConstantValue);
}
#nullable disable

private static LambdaConversionResult IsAnonymousFunctionCompatibleWithDelegate(UnboundLambda anonymousFunction, TypeSymbol type)
{
Expand Down Expand Up @@ -1785,6 +1788,7 @@ private static int GetNumericTypeIndex(SpecialType specialType)
}
}

#nullable enable
private static bool HasImplicitNumericConversion(TypeSymbol source, TypeSymbol destination)
{
Debug.Assert((object)source != null);
Expand Down Expand Up @@ -1827,7 +1831,7 @@ private static bool HasExplicitNumericConversion(TypeSymbol source, TypeSymbol d
return s_explicitNumericConversions[sourceIndex, destinationIndex];
}

public static bool IsConstantNumericZero(ConstantValue value)
private static bool IsConstantNumericZero(ConstantValue value)
{
switch (value.Discriminator)
{
Expand All @@ -1838,12 +1842,14 @@ public static bool IsConstantNumericZero(ConstantValue value)
case ConstantValueTypeDiscriminator.Int16:
return value.Int16Value == 0;
case ConstantValueTypeDiscriminator.Int32:
case ConstantValueTypeDiscriminator.NInt:
return value.Int32Value == 0;
case ConstantValueTypeDiscriminator.Int64:
return value.Int64Value == 0;
case ConstantValueTypeDiscriminator.UInt16:
return value.UInt16Value == 0;
case ConstantValueTypeDiscriminator.UInt32:
case ConstantValueTypeDiscriminator.NUInt:
return value.UInt32Value == 0;
case ConstantValueTypeDiscriminator.UInt64:
return value.UInt64Value == 0;
Expand All @@ -1856,9 +1862,9 @@ public static bool IsConstantNumericZero(ConstantValue value)
return false;
}

public static bool IsNumericType(SpecialType specialType)
private static bool IsNumericType(TypeSymbol type)
{
switch (specialType)
switch (type.SpecialType)
{
case SpecialType.System_Char:
case SpecialType.System_SByte:
Expand All @@ -1872,6 +1878,8 @@ public static bool IsNumericType(SpecialType specialType)
case SpecialType.System_Single:
case SpecialType.System_Double:
case SpecialType.System_Decimal:
case SpecialType.System_IntPtr when type.IsNativeIntegerType:
case SpecialType.System_UIntPtr when type.IsNativeIntegerType:
return true;
default:
return false;
Expand Down Expand Up @@ -1970,16 +1978,16 @@ private static bool HasExplicitEnumerationConversion(TypeSymbol source, TypeSymb
Debug.Assert((object)destination != null);

// SPEC: The explicit enumeration conversions are:
// SPEC: From sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, or decimal to any enum-type.
// SPEC: From any enum-type to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, or decimal.
// SPEC: From sbyte, byte, short, ushort, int, uint, long, ulong, nint, nuint, char, float, double, or decimal to any enum-type.
// SPEC: From any enum-type to sbyte, byte, short, ushort, int, uint, long, ulong, nint, nuint, char, float, double, or decimal.
// SPEC: From any enum-type to any other enum-type.

if (IsNumericType(source.SpecialType) && destination.IsEnumType())
if (IsNumericType(source) && destination.IsEnumType())
{
return true;
}

if (IsNumericType(destination.SpecialType) && source.IsEnumType())
if (IsNumericType(destination) && source.IsEnumType())
{
return true;
}
Expand All @@ -1991,6 +1999,7 @@ private static bool HasExplicitEnumerationConversion(TypeSymbol source, TypeSymb

return false;
}
#nullable disable

private Conversion ClassifyImplicitNullableConversion(TypeSymbol source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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 enable

using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;

namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed partial class LocalRewriter
{
public override BoundNode? VisitFunctionPointerInvocation(BoundFunctionPointerInvocation node)
{
var rewrittenExpression = VisitExpression(node.InvokedExpression);
var rewrittenArgs = VisitList(node.Arguments);

MethodSymbol functionPointer = node.FunctionPointer.Signature;
var argumentRefKindsOpt = node.ArgumentRefKindsOpt;
rewrittenArgs = MakeArguments(
node.Syntax,
rewrittenArgs,
functionPointer,
functionPointer,
expanded: false,
argsToParamsOpt: default,
ref argumentRefKindsOpt,
out ImmutableArray<LocalSymbol> temps,
invokedAsExtensionMethod: false,
enableCallerInfo: ThreeState.False);

node = node.Update(rewrittenExpression, rewrittenArgs, argumentRefKindsOpt, node.ResultKind, node.Type);

if (temps.IsDefaultOrEmpty)
{
return node;
}

return new BoundSequence(node.Syntax, temps, sideEffects: ImmutableArray<BoundExpression>.Empty, node, node.Type);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,8 @@ internal static bool ContainsOnlyEmptyConstraintClauses(this ImmutableArray<Type
}

// Returns true if constraintClauses was updated with value.
// Returns false if constraintClauses already had a value with expected 'IgnoresNullableContext'
// or was updated to a value with the expected 'IgnoresNullableContext' value on another thread.
// Returns false if constraintClauses already had a value with sufficient 'IgnoresNullableContext'
// or was updated to a value with sufficient 'IgnoresNullableContext' on another thread.
internal static bool InterlockedUpdate(ref ImmutableArray<TypeParameterConstraintClause> constraintClauses, ImmutableArray<TypeParameterConstraintClause> value)
{
bool canIgnoreNullableContext = value.IgnoresNullableContext();
Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ internal static bool HasValue(this TypeParameterBounds? boundsOpt, bool canIgnor
}

// Returns true if bounds was updated with value.
// Returns false if bounds already had a value with expected 'IgnoresNullableContext'
// or was updated to a value with the expected 'IgnoresNullableContext' value on another thread.
// Returns false if bounds already had a value with sufficient 'IgnoresNullableContext'
// or was updated to a value with sufficient 'IgnoresNullableContext' on another thread.
internal static bool InterlockedUpdate(ref TypeParameterBounds? bounds, TypeParameterBounds? value)
{
bool canIgnoreNullableContext = (value?.IgnoresNullableContext == true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10778,6 +10778,96 @@ public static void M2()
Assert.Equal(ConversionKind.AnonymousFunction, conversion.Kind);
}

[Fact, WorkItem(47487, "https://github.com/dotnet/roslyn/issues/47487")]
public void InAndRefParameter()
{
var verifier = CompileAndVerifyFunctionPointers(@"
using System;
unsafe
{
delegate*<in int, ref char, void> F = &Test;
char c = 'a';
F(int.MaxValue, ref c);
}
static void Test(in int b, ref char c)
{
Console.WriteLine($""b = {b}, c = {c}"");
}
", expectedOutput: "b = 2147483647, c = a");

verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 27 (0x1b)
.maxstack 3
.locals init (char V_0, //c
delegate*<in int, ref char, void> V_1,
int V_2)
IL_0000: ldftn ""void <Program>$.<<Main>$>g__Test|0_0(in int, ref char)""
IL_0006: ldc.i4.s 97
IL_0008: stloc.0
IL_0009: stloc.1
IL_000a: ldc.i4 0x7fffffff
IL_000f: stloc.2
IL_0010: ldloca.s V_2
IL_0012: ldloca.s V_0
IL_0014: ldloc.1
IL_0015: calli ""delegate*<in int, ref char, void>""
IL_001a: ret
}
");
}

[Fact, WorkItem(47487, "https://github.com/dotnet/roslyn/issues/47487")]
public void OutDiscard()
{
var verifier = CompileAndVerifyFunctionPointers(@"
using System;
unsafe
{
delegate*<out int, out int, void> F = &Test;
F(out var i1, out _);
F(out _, out var i2);
Console.Write(i1);
Console.Write(i2);
}
static void Test(out int i1, out int i2)
{
i1 = 1;
i2 = 2;
}
", expectedOutput: "12");

verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 42 (0x2a)
.maxstack 4
.locals init (int V_0, //i1
int V_1, //i2
int V_2,
delegate*<out int, out int, void> V_3)
IL_0000: ldftn ""void <Program>$.<<Main>$>g__Test|0_0(out int, out int)""
IL_0006: dup
IL_0007: stloc.3
IL_0008: ldloca.s V_0
IL_000a: ldloca.s V_2
IL_000c: ldloc.3
IL_000d: calli ""delegate*<out int, out int, void>""
IL_0012: stloc.3
IL_0013: ldloca.s V_2
IL_0015: ldloca.s V_1
IL_0017: ldloc.3
IL_0018: calli ""delegate*<out int, out int, void>""
IL_001d: ldloc.0
IL_001e: call ""void System.Console.Write(int)""
IL_0023: ldloc.1
IL_0024: call ""void System.Console.Write(int)""
IL_0029: ret
}
");
}

private static readonly Guid s_guid = new Guid("97F4DBD4-F6D1-4FAD-91B3-1001F92068E5");
private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201);

Expand Down
Loading

0 comments on commit 0d0ca13

Please sign in to comment.