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

Fix IArgument.InConversion/OutConversion #21445

Merged
merged 25 commits into from
Sep 12, 2017

Conversation

genlu
Copy link
Member

@genlu genlu commented Aug 11, 2017

Fix #18548. Changed the In/OutConversion from IConversionExpression to CommonConversion (added in #21040 )

    public interface IArgument : IOperation
    {
        /// <summary>
        /// Kind of argument.
        /// </summary>
        ArgumentKind ArgumentKind { get; }
        /// <summary>
        /// Parameter the argument matches.
        /// </summary>
        IParameterSymbol Parameter { get; }
        /// <summary>
        /// Value supplied for the argument.
        /// </summary>
        IOperation Value { get; }
        /// <summary>
        /// Information of the conversion applied to the argument value passing it into the target method. Applicable only to VB Reference arguments.
        /// </summary>
        CommonConversion InConversion { get; }
        /// <summary>
        /// Information of the conversion applied to the argument value after the invocation. Applicable only to VB Reference arguments.
        /// </summary>
        CommonConversion OutConversion { get; }
    }

@genlu
Copy link
Member Author

genlu commented Aug 11, 2017

I think this is mostly done. Please review @AlekseyTs @cston @dotnet/analyzer-ioperation

@genlu
Copy link
Member Author

genlu commented Aug 11, 2017

windows_debug_unit64_prtest failure is probably another instance of #14592:
https://ci.dot.net/job/dotnet_roslyn/job/features_ioperation/job/windows_debug_unit64_prtest/463/


namespace Microsoft.CodeAnalysis.CSharp
{
internal abstract class BaseCSharpArgument : BaseArgument, IArgument
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BaseArgument already implements IArgument.


Public Overrides ReadOnly Property InConversion As [Optional](Of CommonConversion)
Get
Return If(InConversionInternal = Nothing, New [Optional](Of CommonConversion)(), InConversionInternal.ToCommonConversion())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use Nothing instead of New [Optional](Of CommonConversion)(). Same comment for OutConversion below.

''' </summary>
''' <param name="argument">The argument to get original info from.</param>
''' <returns>The underlying <see cref="Conversion"/> of the InConversion.</returns>
''' <exception cref="InvalidCastException">If the <see cref="IArgument"/> was not created from Visual Basic code.</exception>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods throw ArgumentException rather than InvalidCastException.

/// </summary>
IOperation InConversion { get; }
Optional<CommonConversion> InConversion { get; }
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional [](start = 8, length = 26)

It doesn't look like it is a common pattern to use Optional<T> in IOperation API. Would it be better to use identity conversion for situations when no conversion is needed? #Closed


Public Overrides ReadOnly Property InConversion As [Optional](Of CommonConversion)
Get
Return If(InConversionInternal = Nothing, New [Optional](Of CommonConversion)(), InConversionInternal.ToCommonConversion())
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InConversionInternal = Nothing [](start = 26, length = 30)

Conversion is a structure. What does it mean to compare a structure with Nothing and why is it the right thing to do here? #Closed


Public Overrides ReadOnly Property OutConversion As [Optional](Of CommonConversion)
Get
Return If(OutConversionInternal = Nothing, New [Optional](Of CommonConversion)(), OutConversionInternal.ToCommonConversion())
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OutConversionInternal = Nothing [](start = 26, length = 31)

Same issue around Nothing. #Closed

If expression.Kind = BoundKind.Conversion Then
Dim conversion = DirectCast(expression, BoundConversion)
Dim method As MethodSymbol = Nothing
If conversion.Operand.Kind = BoundKind.UserDefinedConversion Then
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conversion.Operand.Kind = BoundKind.UserDefinedConversion [](start = 19, length = 57)

It feels like we should also make sure that the conversion kind for the conversion node is user-defined conversion. #Closed

@@ -51,9 +51,7 @@ static void Test2(int y, params int[] x)
IArgument (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument) (Syntax: 'null')
IConversionExpression (Implicit, TryCast: False, Unchecked) (OperationKind.ConversionExpression, Type: System.Int32[], Constant: null) (Syntax: 'null')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
Operand: ILiteralExpression (Text: null) (OperationKind.LiteralExpression, Type: null, Constant: null) (Syntax: 'null')
InConversion: null
OutConversion: null");
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like these properties should still be validated. #Closed

@@ -835,5 +758,110 @@ BC30272: 'y' is not a parameter of 'Public Sub M2(x As Integer)'.
VerifyOperationTreeAndDiagnosticsForTest(Of InvocationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics)
End Sub



<CompilerTrait(CompilerFeature.IOperation)>
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<CompilerTrait(CompilerFeature.IOperation)> [](start = 8, length = 43)

It looks like there are three new lines between this test and the one above. We usually use one line to separate tests. #Closed


<CompilerTrait(CompilerFeature.IOperation)>
<Fact>
Public Sub InOutConversionUserDefined()
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InOutConversionUserDefined [](start = 19, length = 26)

It would be good to have tests for scenarios when standard conversions are involved into user-defined conversion, either for the input value, or for the method's return value. The cases when either BoundUserDefinedConversion.InConversionOpt, or BoundUserDefinedConversion.OutConversionOpt are not null. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a test in the last commit. Is that what you suggested?

@@ -639,9 +639,23 @@ public override void VisitArgument(IArgument operation)
LogString(")");
LogCommonPropertiesAndNewLine(operation);

if (operation.InConversion.HasValue)
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (operation.InConversion.HasValue) [](start = 12, length = 36)

I think for the purpose of testing it is better to dump all properties regardless of their values. Usually people don't think about things they do not see. An absence of a value should be verified against expectations as well. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Aug 14, 2017

Done with review pass. #Closed

@genlu
Copy link
Member Author

genlu commented Sep 5, 2017

Ping... @AlekseyTs @cston

@genlu
Copy link
Member Author

genlu commented Sep 7, 2017

@AlekseyTs Added tests for extension methods

@AlekseyTs
Copy link
Contributor

@genlu It looks like there are some legitimate test failures.

Return (Nothing, Nothing)
End If

Dim tree = (From t In compilation.SyntaxTrees Where t.FilePath = fileName).Single()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dim tree = (From t In compilation.SyntaxTrees Where t.FilePath = fileName).Single() [](start = 8, length = 83)

Why so complex? Would node.SyntaxTree work?

Dim semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees(0))

Dim expectedInKind = ConversionKind.Widening Or ConversionKind.UserDefined
Dim exptectedInMethod = CType(semanticModel.GetDeclaredSymbolFromSyntaxNode(operatorNodes(0)), IMethodSymbol)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CType(semanticModel.GetDeclaredSymbolFromSyntaxNode(operatorNodes(0)), IMethodSymbol) [](start = 36, length = 85)

This looks more complicated than it should be. There is no need to use semantic model to find methods, I believe that could be done by name.


<CompilerTrait(CompilerFeature.IOperation)>
<Fact>
Public Sub GettingInOutConverionFromVBArgument()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GettingInOutConverionFromVBArgument [](start = 19, length = 35)

There is probably a value in testing clone operation, consider keeping the TestCloneInOutConversion unit-test from iteration 21.

@AlekseyTs
Copy link
Contributor

Done with review pass (iteration 22). The only blocking issue is the failing test.

@genlu genlu closed this Sep 7, 2017
@genlu genlu reopened this Sep 7, 2017
@genlu
Copy link
Member Author

genlu commented Sep 7, 2017

@dotnet/roslyn-infrastructure It seems the tests are not triggered by new commits. Any ideas?

@AlekseyTs
Copy link
Contributor

It seems the tests are not triggered by new commits. Any ideas?

Looking into this.

@genlu
Copy link
Member Author

genlu commented Sep 7, 2017

@cston Can I get another review from compiler team please?


[CompilerTrait(CompilerFeature.IOperation)]
[Fact]
public void GettingInOutConverionFromCSharpArgumentShouldThrowException()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: Conversion


Assert.Throws<ArgumentException>(() => argument.GetInConversion());
Assert.Throws<ArgumentException>(() => argument.GetOutConversion());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are GetInConversion and GetOutConversion defined? And why do they throw ArgumentException in this case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are extension methods for VB only (defined in MS.CA.VB.dll), as it returns VB Conversion. In this test we pass in an IArgument from C# code, therefore it throws.

Copy link
Member

@cston cston Sep 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Perhaps add a comment here that we're calling VB methods so it's clear why we expect exceptions to be thrown.

public override CommonConversion OutConversion => new CommonConversion(exists: true, isIdentity: true, isNumeric: false, isReference: false, methodSymbol: null);
}

internal sealed partial class CSharpArgument : BaseCSharpArgument
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these CSharpArgument classes need to be partial?

Return (operation, node)
Else
Return (Nothing, Nothing)
End If
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is If operation IsNot Nothing necessary or could this method Return (operation, node) always?

inConversion:=Nothing,
outConversion:=Nothing,
inConversion:=New Conversion(Conversions.Identity),
outConversion:=New Conversion(Conversions.Identity),
semanticModel:=_semanticModel,
syntax:=value.Syntax,
type:=Nothing,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the only difference between If and Else is kind. Consider calculating kind inside the If and move the remainder outside the If.

@@ -2245,6 +2245,7 @@ static void M2(int x)
var invocation = (IInvocationExpression)operation;
var argument = invocation.ArgumentsInEvaluationOrder[0];

// We are calling VB extension methods on IArgument in C# code, therefore exception is expteced here.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: expected

Return New VisualBasicArgument(
kind,
parameter,
Create(argument),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value

@@ -105,47 +105,37 @@ Namespace Microsoft.CodeAnalysis.Semantics
isImplicit:=isImplicit)
Case Else
Dim lastParameterIndex = parameters.Length - 1
Dim kind As ArgumentKind
Dim parameter As ParameterSymbol
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameter = parameters(index) in both branches.

@genlu genlu merged commit b3cacb0 into dotnet:features/ioperation Sep 12, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants