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

Adding IsConst modreq on ref readonly signatures #19658

Merged
merged 6 commits into from
Jun 23, 2017
Merged

Adding IsConst modreq on ref readonly signatures #19658

merged 6 commits into from
Jun 23, 2017

Conversation

OmarTawfik
Copy link
Contributor

@OmarTawfik OmarTawfik commented May 19, 2017

Contributes to #17287

@OmarTawfik OmarTawfik added Area-Compilers Feature - Readonly References Readonly References PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. labels May 19, 2017
internal override bool IsConstModifierType(PEModuleSymbol moduleSymbol, TypeSymbol type)
{
return type.ToDisplayString() == WellKnownTypes.GetMetadataName(WellKnownType.System_Runtime_CompilerServices_IsConst);
}
Copy link
Contributor Author

@OmarTawfik OmarTawfik May 19, 2017

Choose a reason for hiding this comment

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

Comparing symbols by full name is probably not be the best way to do it. Looking up a better alternative. #Closed

Copy link
Member

@jaredpar jaredpar May 22, 2017

Choose a reason for hiding this comment

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

Consider a similar scenario like IsVolatileModfifierType. Can we re-use that approach here? #Resolved

Copy link
Contributor Author

@OmarTawfik OmarTawfik May 22, 2017

Choose a reason for hiding this comment

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

Unfortunately, no. Unless there is something I'm missing, IsConst is not a special library type :(


In reply to: 117829472 [](ancestors = 117829472)

Copy link
Member

@cston cston May 22, 2017

Choose a reason for hiding this comment

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

Perhaps the same approach as SymbolFactory.GetSystemTypeSymbol. #Resolved

Copy link
Member

Choose a reason for hiding this comment

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

we need a bug or a PROTOTYPE marker to track this


In reply to: 117561528 [](ancestors = 117561528)

Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

This seems simple enough to fix now vs. needing a PROTOTYPE comment to fix later. #Resolved

Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

Comparing symbols by full name is probably not be the best way to do it. Looking up a better alternative.

Given that this is not a SpecialType, I think name comparison is the only right way to do that. If performance is a concern we can compare type name and namespace names separately, then calling ToDisplayString won't be needed. #Closed

Copy link
Member

Choose a reason for hiding this comment

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

If going with name comparing, should definitely compare namespace/type name parts separately. I think ToDisplay will concat them every time


In reply to: 118063143 [](ancestors = 118063143)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Planning on fixing now.


In reply to: 117888944 [](ancestors = 117888944,117561528)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From what I tracked down, it ends up doing a lookup in NamespaceOrTypeSymbol based on string comparison as well. Will separate the comparison to namespace/type pair to improve performance.


In reply to: 117866143 [](ancestors = 117866143)


for (;;)
customModifiers = DecodeModifiersOrThrow(ref signatureReader, out typeCode, acceptRequiredModifier: type =>
Copy link
Contributor Author

@OmarTawfik OmarTawfik May 19, 2017

Choose a reason for hiding this comment

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

DecodeModifiersOrThrow [](start = 34, length = 22)

This was refactored since it shares the same behavior as DecodeModifiersOrThrow(), making use of the additional parameter. #Closed

@OmarTawfik OmarTawfik removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label May 19, 2017
@OmarTawfik
Copy link
Contributor Author

OmarTawfik commented May 22, 2017

cc @VSadov @dotnet/roslyn-compiler #Closed

out _lazyParameters, alsoCopyParamsModifier: true);
}
}
else if (_refKind == RefKind.RefReadOnly && (this.IsVirtual || this.IsAbstract))
{
var isConst = withTypeParamsBinder.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsConst, diagnostics, syntax);
Copy link
Member

@jaredpar jaredpar May 22, 2017

Choose a reason for hiding this comment

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

What if the type is missing? Consider that custom mscorlibs may not have this type. #ByDesign

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I've a test that specifically looks for that. Check ProperErrorsArePropagatedIfMscorlibIsConstIsNotAvailable in IsConstModifierTests.cs.
The method Binder.GetWellKnownType() will report such errors to the passed diagnostics bag.


In reply to: 117828511 [](ancestors = 117828511)

Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

Consider the name isConstType vs. isConst. The former is a bit more descriptive and seems more consistent with other names in the method. The latter can be misread as describing the mutable state of a value. #Resolved

@@ -48,6 +50,25 @@ internal abstract class SourceParameterSymbol : SourceParameterSymbolBase
identifier.Parent.GetLocation());
}

if (shouldPlaceIsConstModifier && refKind == RefKind.RefReadOnly && (owner.IsVirtual || owner.IsAbstract))
{
var isConst = context.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsConst, declarationDiagnostics, syntax);
Copy link
Member

@jaredpar jaredpar May 22, 2017

Choose a reason for hiding this comment

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

What if the type is missing? consider custom mscorlib may not have this type. #ByDesign

@@ -273,6 +273,14 @@ internal sealed class SourcePropertySymbol : PropertySymbol, IAttributeTargetSym
_lazyParameters = CustomModifierUtils.CopyParameterCustomModifiers(overriddenOrImplementedProperty.Parameters, _lazyParameters, alsoCopyParamsModifier: isOverride);
}
}
else if (_refKind == RefKind.RefReadOnly && (this.IsVirtual || this.IsAbstract))
{
var isConst = bodyBinder.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsConst, diagnostics, syntax);
Copy link
Member

@jaredpar jaredpar May 22, 2017

Choose a reason for hiding this comment

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

Same #ByDesign

@@ -49,6 +49,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Return False
End Function

Friend Overrides Function IsConstModifierType(moduleSymbol As PEModuleSymbol, type As TypeSymbol) As Boolean
' VB doesn't deal with ref-readonly parameters or return-types.
Return False
Copy link
Member

@jaredpar jaredpar May 22, 2017

Choose a reason for hiding this comment

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

Don't understand why we are returning False here. Even if VB doesn't deal with these typse returning False here still seems wrong. If the function isn't implemented it should throw, not return the (potentially) wrong answer. #ByDesign

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This means that if VB MetadataDecoder tries to read a symbol with a modreq of type IsConst, it will return False meaning it doesn't support it, and the symbol will be marked appropriately. Check IsVolatileModifierType() in the same file.


In reply to: 117828980 [](ancestors = 117828980)

Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

If that's the case then we should consider renaming both of these methods. The name simply does not match up to the actual implementation. Consider this code

var isConst = IsConstModifierType(type);

99% of developers who look at that line are going to interpret this as determining if type is the const modifier. In reality it's detecting if a) it's the const modifier and b) the present language supports it. The 1% who will understand the behavior are those who realize the name of the method is wrong.
#Resolved

Copy link
Contributor Author

@OmarTawfik OmarTawfik May 24, 2017

Choose a reason for hiding this comment

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

Will rename both to IsAcceptedXXXXModifierType


In reply to: 118021028 [](ancestors = 118021028)

internal override bool IsConstModifierType(PEModuleSymbol moduleSymbol, TypeSymbol type)
{
return type.ToDisplayString() == WellKnownTypes.GetMetadataName(WellKnownType.System_Runtime_CompilerServices_IsConst);
}
Copy link
Member

@jaredpar jaredpar May 22, 2017

Choose a reason for hiding this comment

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

Consider a similar scenario like IsVolatileModfifierType. Can we re-use that approach here? #Resolved

}

[Fact]
public void ProperErrorsArePropagatedIfMscorlibIsConstIsNotAvailable()
Copy link
Contributor Author

@OmarTawfik OmarTawfik May 22, 2017

Choose a reason for hiding this comment

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

ProperErrorsArePropagatedIfMscorlibIsConstIsNotAvailable [](start = 20, length = 56)

Note to self: duplicate tests for other symbol types and the same error. #Closed

@@ -273,6 +273,14 @@ internal sealed class SourcePropertySymbol : PropertySymbol, IAttributeTargetSym
_lazyParameters = CustomModifierUtils.CopyParameterCustomModifiers(overriddenOrImplementedProperty.Parameters, _lazyParameters, alsoCopyParamsModifier: isOverride);
}
}
else if (_refKind == RefKind.RefReadOnly && (this.IsVirtual || this.IsAbstract))
Copy link
Member

@VSadov VSadov May 22, 2017

Choose a reason for hiding this comment

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

does this work with interface implementations? explicit/implicit? #Resolved

Copy link
Member

Choose a reason for hiding this comment

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

I think we need some tests for interface implementations


In reply to: 117863982 [](ancestors = 117863982)

@@ -249,6 +249,7 @@ private sealed class InvokeMethod : SourceDelegateMethodSymbol
binder, this, syntax.ParameterList, out arglistToken,
allowRefOrOut: true,
allowThis: false,
shouldPlaceIsConstModifier: false,
Copy link
Member

@VSadov VSadov May 23, 2017

Choose a reason for hiding this comment

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

I think we want "true" here. Otherwise old compiler may convert methods with regular "ref" to delegate types with "ref readonly". #Resolved

Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

I think we want "true" here. Otherwise old compiler may convert methods with regular "ref" to delegate types with "ref readonly".

Please add VB test for this scenario. #Closed

@VSadov
Copy link
Member

VSadov commented May 23, 2017

I am done with a review pass. Mostly good. I had some comments, that I think are actionable.


In reply to: 303181737 [](ancestors = 303181737)

{
// This cannot be placed on CustomModifiers, just RefCustomModifiers
throw new UnsupportedSignatureContent();
}
Copy link
Member

@cston cston May 23, 2017

Choose a reason for hiding this comment

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

Is isConstFound needed or could the check above be replaced by else if (info.CustomModifiers.Length > 0)? Then the delegate to DecodeModifiersOrThrow can be simplified to avoid the closure class. Similar comment for isVolatileFound in DecodeFieldSignature. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will remove the need for capturing, but we still need that isConstFound value since we allow optional modifiers, just not required ones.


In reply to: 117907098 [](ancestors = 117907098)

@@ -107,5 +108,188 @@ End Class

CompileAndVerify(comp, expectedOutput:=<![CDATA[2]]>)
End Sub

<Fact>
Public Sub NonExtensibleReadOnlySignaturesAreRead()
Copy link
Member

@cston cston May 23, 2017

Choose a reason for hiding this comment

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

Perhaps Virtual rather than Extensible, here and below. #Resolved

public int this[ref readonly int x] => x;
}";

var options = TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All);
Copy link
Member

@cston cston May 23, 2017

Choose a reason for hiding this comment

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

Is MetadataImportOptions.All needed here, or in tests below? #Resolved

out _lazyParameters, alsoCopyParamsModifier: true);
}
}
else if (_refKind == RefKind.RefReadOnly && (this.IsVirtual || this.IsAbstract))
Copy link
Member

@cston cston May 23, 2017

Choose a reason for hiding this comment

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

Are we including IsConst on interface methods? #Resolved

Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

Yes: virtual method parameters, returns, interface methods in any position and delegates. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Parameters handle both parameters and returns. Will add tests for interfaces and delegates.


In reply to: 118018517 [](ancestors = 118018517)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add tests to both implicit and explicit interface implementations


In reply to: 118016179 [](ancestors = 118016179)

internal override bool IsConstModifierType(PEModuleSymbol moduleSymbol, TypeSymbol type)
{
return type.ToDisplayString() == WellKnownTypes.GetMetadataName(WellKnownType.System_Runtime_CompilerServices_IsConst);
}
Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

This seems simple enough to fix now vs. needing a PROTOTYPE comment to fix later. #Resolved

@@ -20,7 +20,8 @@ internal static class ParameterHelpers
out SyntaxToken arglistToken,
DiagnosticBag diagnostics,
bool allowRefOrOut,
bool allowThis)
bool allowThis,
bool shouldPlaceIsConstModifier)
Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

Consider shoudEmit vs. shouldPlace. #Resolved

Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

Consider shoudEmit vs. shouldPlace.

Perhaps simply "addIsConstModifier". #Closed

out _lazyParameters, alsoCopyParamsModifier: true);
}
}
else if (_refKind == RefKind.RefReadOnly && (this.IsVirtual || this.IsAbstract))
Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

Yes: virtual method parameters, returns, interface methods in any position and delegates. #Resolved

var isConst = IsConstModifierType(type);
isConstFound |= isConst;
return isConst;
});
Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

This lambda is capturing hence is adding two allocations to each call to DecodeModifiersOrThrow. Is this a sensitive enough area of the code that we should consider a non-allocating solution? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will move to a version that has less allocations, also adding an extra overload for the less-traversed path.


In reply to: 118019729 [](ancestors = 118019729)

@@ -49,6 +49,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Return False
End Function

Friend Overrides Function IsConstModifierType(moduleSymbol As PEModuleSymbol, type As TypeSymbol) As Boolean
' VB doesn't deal with ref-readonly parameters or return-types.
Return False
Copy link
Member

@jaredpar jaredpar May 23, 2017

Choose a reason for hiding this comment

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

If that's the case then we should consider renaming both of these methods. The name simply does not match up to the actual implementation. Consider this code

var isConst = IsConstModifierType(type);

99% of developers who look at that line are going to interpret this as determining if type is the const modifier. In reality it's detecting if a) it's the const modifier and b) the present language supports it. The 1% who will understand the behavior are those who realize the name of the method is wrong.
#Resolved

private ImmutableArray<ModifierInfo<TypeSymbol>> DecodeModifiersOrThrow(
ref BlobReader signatureReader,
out SignatureTypeCode typeCode,
Func<TypeSymbol, bool> acceptRequiredModifier = null)
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

Func<TypeSymbol, bool> acceptRequiredModifier = null [](start = 12, length = 52)

This feels too complicated. I think we can simply pas a boolean whether IsConst modifier should be accepted as a mod_req or not. #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than making changes to this function, I would instead modify DecodeParameterOrThrow to specially handle IsConst modifier in the manner DecodeFieldSignature used to do that for IsVolatile and would keep this function and DecodeFieldSignature unchanged.


In reply to: 118052362 [](ancestors = 118052362)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will try to introduce in the next iteration a simpler version that doesn't use capturing lambdas. I don't like to duplicate the same logic in 3 places (DecodeModifiers, DecodeParameters, DecodeFields).


In reply to: 118055994 [](ancestors = 118055994,118052362)

info.CustomModifiers = DecodeModifiersOrThrow(ref signatureReader, out typeCode);
}
else if (isConstFound)
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

else if (isConstFound) [](start = 12, length = 22)

We could simply check for presence of any required modifiers in info.CustomModifiers. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will try to refactor it so that we don't need to do the extra enumeration.


In reply to: 118054332 [](ancestors = 118054332)

SignatureTypeCode typeCode;
ArrayBuilder<ModifierInfo<TypeSymbol>> customModifierBuilder = null;
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

ArrayBuilder<ModifierInfo> customModifierBuilder = null; [](start = 16, length = 68)

I would revert changes in this function, it doesn't look like we want any behavior change here. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will try to introduce in the next iteration a simpler version that doesn't use capturing lambdas. I don't like to duplicate the same logic in 3 places (DecodeModifiers, DecodeParameters, DecodeFields).


In reply to: 118054960 [](ancestors = 118054960)

@@ -273,6 +273,7 @@ public virtual void Visit(IMethodDefinition method)
{
this.Visit(method.GetReturnValueAttributes(Context));
this.Visit(method.ReturnValueCustomModifiers);
this.Visit(method.RefCustomModifiers);
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

this.Visit(method.RefCustomModifiers); [](start = 12, length = 38)

It feels like RefCustomModifiers should be visited before ReturnValueCustomModifiers. Also, it looks like there are two more places in ReferenceIndexerBase.cs that should be adjusted in a similar way. #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like there is one more place in ReferenceDependencyWalker.cs as well.


In reply to: 118057254 [](ancestors = 118057254)

@@ -412,6 +413,7 @@ public virtual void Visit(IParameterDefinition parameterDefinition)
Debug.Assert((marshalling != null || !parameterDefinition.MarshallingDescriptor.IsDefaultOrEmpty) == parameterDefinition.IsMarshalledExplicitly);

this.Visit(parameterDefinition.GetAttributes(Context));
this.Visit(parameterDefinition.RefCustomModifiers);
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

this.Visit(parameterDefinition.RefCustomModifiers); [](start = 12, length = 51)

It looks like there is one more place in ReferenceDependencyWalker.cs that should be adjusted in a similar way. And in public virtual void Visit(IParameterTypeInformation parameterTypeInformation) in this type as well. #Closed

@@ -63,7 +63,7 @@ public static bool HasRefOrOutParameter(this PropertySymbol property)
{
foreach (ParameterSymbol param in property.Parameters)
{
if (param.RefKind != RefKind.None)
if (param.RefKind == RefKind.Ref || param.RefKind == RefKind.Out)
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

if (param.RefKind == RefKind.Ref || param.RefKind == RefKind.Out) [](start = 16, length = 65)

Did you add a test backing this change? Could you point to the test(s)? #Closed

Copy link
Contributor Author

@OmarTawfik OmarTawfik May 25, 2017

Choose a reason for hiding this comment

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

Adding IsConstModReqIsConsumedInRefCustomModifiersPosition_Indexers_ReturnTypes. This change basically allows to pass ref-readonly arguments to indexer methods. Passing ordinary arguments is the same to properties as ref-readonly arguments.


In reply to: 118061963 [](ancestors = 118061963)

Copy link
Contributor

Choose a reason for hiding this comment

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

Adding IsConstModReqIsConsumedInRefCustomModifiersPosition_Indexers_ReturnTypes. This change basically allows to pass ref-readonly arguments to indexer methods. Passing ordinary arguments is the same to properties as ref-readonly arguments.

I couldn't find the test, what file it should be in?


In reply to: 118609191 [](ancestors = 118609191,118061963)

Copy link
Contributor Author

@OmarTawfik OmarTawfik Jun 5, 2017

Choose a reason for hiding this comment

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

File IsConstModifierTests.cs in C# emit tests project. You can look forIsConstModReqIsConsumedInRefCustomModifiersPosition_Code_Indexers_ReturnTypes now.


In reply to: 119789809 [](ancestors = 119789809,118609191,118061963)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correction: IsConstModReqIsConsumedInRefCustomModifiersPosition_Code_Indexers_Parameters*


In reply to: 120218968 [](ancestors = 120218968,119789809,118609191,118061963)

@@ -107,5 +108,188 @@ End Class

CompileAndVerify(comp, expectedOutput:=<![CDATA[2]]>)
End Sub

<Fact>
Public Sub NonExtensibleReadOnlySignaturesAreRead()
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

Public Sub NonExtensibleReadOnlySignaturesAreRead() [](start = 8, length = 51)

Consider moving all these tests into a new file dedicated to ReadonlyRef feature. #Closed

Dim reference = CreateCSharpCompilation("
public class TestRef
{
public void M(ref readonly int x)
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

public void M(ref readonly int x) [](start = 4, length = 33)

This test covers ref readonly parameter. Do we have a similar test for return? #Closed

Class Test
Shared Sub Main()
Dim obj = New TestRef()
Dim value = obj.M()
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

Dim value = [](start = 8, length = 12)

Consider removing the local, leaving gust the method call. #Closed

public class TestRef
{
private int value = 0;
public virtual ref readonly int P => ref value;
Copy link
Contributor

@AlekseyTs AlekseyTs May 23, 2017

Choose a reason for hiding this comment

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

public virtual ref readonly int P => ref value; [](start = 4, length = 47)

Do we have a test for a non-virtual property? #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 2, 2017

        CompileAndVerify(code, additionalRefs: new[] { reference.EmitToImageReference() }, symbolValidator: module =>

Success scenarios should be executed and runtime behavior should be verified. Applies to all similar tests. #Closed


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:2421 in 42a8f4c. [](commit_id = 42a8f4c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 2, 2017

            var parameter = type.GetMethod("Parent.M").Parameters.Single();

Consider asserting that this method implements the interface. Applies to all similar tests. #Closed


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:2564 in 42a8f4c. [](commit_id = 42a8f4c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 2, 2017

    public void WhenImplementingParentWithModifiersCopyThem_Methods_ReturnTypes_ExplicitInterfaces()

I think for all "copy modifiers" tests it would be interesting to test flavor when compilation define their own IsConst type. Then we actually can observe the copy happening vs. we just added modifiers based on ref readonly usage. #Closed


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:2708 in 42a8f4c. [](commit_id = 42a8f4c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 2, 2017

    public void CreatingLambdasOfDelegatesWithModifiersCanBeExecuted_Parameters()

Similarly should test scenarios when both compilations define their own IsConst type. #Closed


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:3257 in 42a8f4c. [](commit_id = 42a8f4c, deletion_comment = False)

destinationMethod.ReturnsByRef ? constructedSourceMethod.RefCustomModifiers : ImmutableArray<CustomModifier>.Empty);
customModifiers = CustomModifiersTuple.Create(
constructedSourceMethod.ReturnTypeCustomModifiers,
destinationMethod.ReturnsByRef || destinationMethod.ReturnsByRefReadonly ? constructedSourceMethod.RefCustomModifiers : ImmutableArray<CustomModifier>.Empty);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 2, 2017

Choose a reason for hiding this comment

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

destinationMethod.ReturnsByRef || destinationMethod.ReturnsByRefReadonly [](start = 16, length = 73)

Could we simply check if RefKind is None? #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 2, 2017

Done with review pass. #Closed

@@ -167,6 +167,7 @@ private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsB
signatureBinder, this, syntax.ParameterList, out arglistToken,
allowRefOrOut: true,
allowThis: true,
addIsConstModifier: IsVirtual || IsAbstract,
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 2, 2017

Choose a reason for hiding this comment

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

IsVirtual || IsAbst [](start = 36, length = 19)

This should probably include checks for override and explicit implementation, those are virtual (in metadata terms) as well and the difference will be observable for cases when the target method cannot be found, etc. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filed #20053 for that.


In reply to: 119902520 [](ancestors = 119902520)

@@ -1388,7 +1397,7 @@ private TypeSymbol ComputeType(Binder binder, BasePropertyDeclarationSyntax synt
private ImmutableArray<ParameterSymbol> ComputeParameters(Binder binder, BasePropertyDeclarationSyntax syntax, DiagnosticBag diagnostics)
{
var parameterSyntaxOpt = GetParameterListSyntax(syntax);
var parameters = MakeParameters(binder, this, parameterSyntaxOpt, diagnostics);
var parameters = MakeParameters(binder, this, parameterSyntaxOpt, diagnostics, addIsConstModifier: IsVirtual || IsAbstract);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 2, 2017

Choose a reason for hiding this comment

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

IsVirtual || IsAbstract [](start = 111, length = 23)

Same comment as for methods. #Closed

@OmarTawfik
Copy link
Contributor Author

OmarTawfik commented Jun 7, 2017

            var parameter = type.GetMethod("M").Parameters.Single();

This is not an explicit implementation. comment misplaced? If the method is virtual, we don't create explicit implementations. Only for non-virtuals. I modified the other tests.


In reply to: 305697978 [](ancestors = 305697978)


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:2530 in 42a8f4c. [](commit_id = 42a8f4c, deletion_comment = False)

@OmarTawfik
Copy link
Contributor Author

    public void WhenImplementingParentWithModifiersCopyThem_Methods_ReturnTypes_ExplicitInterfaces()

Please check the tests starting with UsingIsConstFromReferenceWhileHavingDuplicateInCompilation_*.
We generate the modreqs based on the available type because (in most cases, unless the interface was specificied explicitly) we don't know which interface this method might belong to.
In these cases, we will generate a proxy function that has the other type.
We can iterate over this behaviour (which I think applies globally, not for this PR only) in #20053


In reply to: 305699094 [](ancestors = 305699094)


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:2708 in 42a8f4c. [](commit_id = 42a8f4c, deletion_comment = False)

@OmarTawfik
Copy link
Contributor Author

OmarTawfik commented Jun 8, 2017

@AlekseyTs comments addressed. #Closed

@OmarTawfik
Copy link
Contributor Author

OmarTawfik commented Jun 8, 2017

@cston @jaredpar @VSadov any other comments? #Closed

if (_refKind == RefKind.RefReadOnly)
{
var isConstType = binder.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsConst, diagnostics, syntax.ReturnType);
_refCustomModifiers = ImmutableArray.Create(CSharpCustomModifier.CreateRequired(isConstType));
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2017

Choose a reason for hiding this comment

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

_refCustomModifiers = ImmutableArray.Create(CSharpCustomModifier.CreateRequired(isConstType)); [](start = 20, length = 94)

It feels like we could simply reuse modifiers from the invoke. #Closed

@@ -342,15 +356,18 @@ internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetReturnTypeAttrib

private sealed class EndInvokeMethod : SourceDelegateMethodSymbol
{
private readonly RefKind refKind;
private readonly RefKind _refKind;
private readonly ImmutableArray<CustomModifier> _refCustomModifiers;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2017

Choose a reason for hiding this comment

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

private readonly ImmutableArray _refCustomModifiers; [](start = 12, length = 68)

Consider replacing two these members with a reference to invoke, then implementation of RefKind and RefCustomModifiers could simply delegate to the invoke. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 9, 2017

        CompileAndVerify(code, additionalRefs: new[] { reference }, expectedOutput: "5");

I noticed that you cloned the entire unit-test in order to test this scenario against compilation reference. This feel like an overkill to me, both scenarios could easily be tested right here:

CompileAndVerify(code, additionalRefs: new[] { compilation1.ToMetedataReference() }, expectedOutput: "5");
CompileAndVerify(code, additionalRefs: new[] { compilation1.EmitToImageReference() }, expectedOutput: "5");

This isn't a blocker, but it causes an unnecessary code duplication and work duplication while tests are executed. #Closed


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:38 in b32dc89. [](commit_id = b32dc89, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 9, 2017

        CompileAndVerify(code, additionalRefs: new[] { reference.EmitToImageReference() }, expectedOutput: "5");

Please add a call (applies to all similar tests)

CompileAndVerify(code, additionalRefs: new[] { reference.ToMetadataReference() }, expectedOutput: "5");
``` #Closed

---
Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:3848 in b32dc89. [](commit_id = b32dc89aaa354d3b23a18534f8b4bbe076c1b51a, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 9, 2017

Done with review pass. #Closed

@VSadov
Copy link
Member

VSadov commented Jun 9, 2017

@OmarTawfik - I have no actionable comments on this. Except - Can we wait with merging this until after the ref-extension are merged in and there is a build that contains them?

This would be the first change that intentionally breaks "compatibility" with old compilers. It would be nice to have a builds before/after - just for comparison reasons.

@jcouv jcouv modified the milestone: 15.6 Jun 12, 2017
@OmarTawfik
Copy link
Contributor Author

        CompileAndVerify(code, additionalRefs: new[] { reference }, expectedOutput: "5");

Tried to isolate the root cause. If a test fails because of the difference between metadata/image references, then one of them should succeed.
But taking a look at the entirety of the tests added, it is going to be a few thousands of lines to maintain. Will refactor.


In reply to: 307460674 [](ancestors = 307460674)


Refers to: src/Compilers/CSharp/Test/Emit/Emit/IsConstModifierTests.cs:38 in b32dc89. [](commit_id = b32dc89, deletion_comment = False)

@OmarTawfik
Copy link
Contributor Author

@AlekseyTs done with latest set of comments.

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM

@VSadov VSadov merged commit 55d359d into dotnet:features/readonly-ref Jun 23, 2017
@OmarTawfik OmarTawfik deleted the isconst-modreqs branch July 19, 2017 18:25
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.

7 participants