-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Conversation
Merge branch 'master'
merge from master
@@ -695,10 +694,6 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC | |||
PRECONDITION( | |||
(!pCtor && gc.refCaType->GetType().IsValueType() && !gc.refCaType->GetType().GetMethodTable()->HasDefaultConstructor()) || | |||
(pCtor == gc.refCaType->GetType().GetMethodTable()->GetDefaultConstructor())); | |||
|
|||
// If we relax this, we need to insure custom attributes construct properly for Nullable<T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this work for Nullable types that this comment is talking about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you mean that the generic argument is nullable so I tried with int? and it works great too
@jkotas Do I need to do more things to get this PR merged? |
@@ -671,7 +671,6 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC | |||
CONTRACTL { | |||
FCALL_CHECK; | |||
PRECONDITION(CheckPointer(pCaTypeUNSAFE)); | |||
PRECONDITION(!pCaTypeUNSAFE->GetType().IsGenericVariable()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this precondition is still valid. This is guarding against something like this:
class G<T>
{
[T] // <-- still disallowed, correct?
class Inner {}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@atsushikan You right sorry I revert this delete and validated it's still work
@atsushikan Could you please take a look at this? There will need to be tests added or updated in corefx. |
What I see here LGTM but the framework has a bunch of overlapping custom-attribute fetching apis and the code isn't as factored for sharing as it could be. Attribute.GetCustomAttribute(*), IsDefined, etc. Can you test some of these as well to make sure all our code paths have been updated? |
@atsushikan what is the best place to write this tests? |
System.Runtime\tests is where you'd add the tests, but this assumes that this new language feature is already enabled in the corefx toolset. If not, you should leave an issue open for writing tests once the feature is available. For now, I just meant test it privately as you've been doing... |
@atsushikan I also made PR for Roslyn dotnet/roslyn#16814 so when this will merge hope also roslyn merge the PR |
Should I be able to say |
@jkotas I'll check this too |
This sounds like appropriate material for an api proposal. It's a bit iffy - it conflates the concept of assignability with instantiation. Note that this would be a breaking change if we don't do it in NS2.0 as in some instances (the GetCustomAttribute() apis off MemberInfo (the ones not "added" by CustomAttributeExtensions) don't do any validation on the passed in attribute type, so this kind of call today would return an empty array (as in "Yessir, none of the attributes on this member are assignable to MyCustomAttribute<>") |
How will this work for serialized custom attribute data? Suppose we have: class FooAttribute<T> : Attribute
{
public T Field;
} Now, I would expect this to work: [Foo<int>(Field = 123)]
class X { } But this shouldn't: [Foo<int?>(Field = 123)]
class Y { } Will the class library fail appropriately? Will Roslyn be checking for this too? |
@MichalStrehovsky roslyn already check this |
But the runtime needs to check for this too. There could be a buggy compiler that emits such metadata blob. We need to make sure it fails as expected (and make sure we have test coverage for that). It's possible the runtime already does handle it, but since this PR is removing some validation that would previously cover it, we need to ensure the new failure modes the removed validation opens us up to are covered as well. |
@MichalStrehovsky I'm working on tests I'll add this scenario thanks |
@atsushikan Please look at my tests https://gist.github.com/AviAvni/3ee62f4c93d33485db880cf01011e0b6 @MichalStrehovsky I tried to make tests that you mentioned by taking the IL from the tests exe with ildasm |
Be careful about distinguishing beween the instance member GetCustomAttributes() and the extension method CustomAttributes() - they're called using the same C# syntax but for reasons that escape me, aren't the same at all internally. It's probably safest to write the tests so that the instance member version is always invoked through the ICustomAttributeProvider interface rather directly from the member, while the extension method is invoke without using the extension method syntax, i.e. rather than writing memberInfo.GetCustomAttribute(typeof(D), inherit: true), write ((ICustomAttributeProvider)memberInfo).GetCustomAttributes(typeof(D), inherit: true) and CustomAttributeExtensions.GetCustomAttribute(memberInfo, typeof(D), inherit: true). That way, it's always clear which one you mean. |
@atsushikan thanks I updated the gist |
@atsushikan now the difference is in line https://gist.github.com/AviAvni/3ee62f4c93d33485db880cf01011e0b6#file-genericattributetests-cs-L187 |
CustomAttributeExtensions.GetCustomAttributes() should never return null. If there are no matching attributes, it should return a 0-length enumeration. |
@@ -0,0 +1,72 @@ | |||
using System; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add license header?
@jkotas I added the license header and the missing spaces sorry |
@AviAvni The change looks good to me now. Thanks! We are too close to snapping 2.1 release and I do not think there is runway to verify this together with the matching C# changes. This will need to wait after 2.1. |
AssertAny(b8, a => (a as MultiAttribute<bool?>)?.Value == null); | ||
|
||
Assert(CustomAttributeExtensions.GetCustomAttributes(programTypeInfo, typeof(MultiAttribute<>), false) == null); | ||
Assert(CustomAttributeExtensions.GetCustomAttributes(programTypeInfo, typeof(MultiAttribute<>), true) == null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you pass in an open attribute type to this api (typeof(MultiAttribute<)
), I think it should either:
- Throw a NotSupportedException saying explicitly that the attribute type cannot be an open type (and for consistency, make Attribute.GetCustomAttributes work the same way) I think this is the preferable option as I can't think of a good use case for passing in an open type here.
or
- Return a zero-length array of type
Attribute[]
.
We shouldn't be returning null
- there is no precedent for this api returning null
.
Edit: Changed ArgumentException
to NotSupportedException
since that's the behavior you see today with the api.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@atsushikan I implemented this on Attribute.GetCustomAttributes and with CustomAttributeExtensions api it throws NotSupportedException as expected
but it not work for ICustomAttributeProvider api is this api need also to throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing in an open type as the attribute type should continue to throw NotSupportedException. See my last comment.
Edit: My bad - returning null
is the NETFX compatible behavior. It was CoreRT that was incompatible.
We should implement the compatible behavior. I just checked on .NETFx – the ICustomAttribute api returns a zero-length array of type Object[] when passed an open type. That’s a bit unfortunate – I’d have preferred a consistent response from all three variants, but compatibility is more important than reporting an obvious programmer error the same way everywhere. So let’s have that variant continue to return an empty Object array.
|
@atsushikan I made the change you asked |
src/mscorlib/src/System/Attribute.cs
Outdated
@@ -459,6 +459,9 @@ public static Attribute[] GetCustomAttributes(MemberInfo element, Type type, boo | |||
if (type == null) | |||
throw new ArgumentNullException(nameof(type)); | |||
|
|||
if (type.IsGenericTypeDefinition) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The api you want is Type.ContainsGenericParameters
. This will catch open types such as G<int, T>
in addition to G<>
.
{ | ||
static int Main(string[] args) | ||
{ | ||
new MultiAttribute<string>("a"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line looks like an accidental leftover.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry
Ah - I just checked the behavior of Attribute.GetCA and CustomAttributeExtensions.GetCA on NETFX and it seems they do return null when passed in an open generic type. It was the CoreRT framework that was throwing Sorry about the bother. |
…bute" This reverts commit 69603dc.
@AviAvni Could you please resolve the conflict? This can be merged now. |
@jkotas conflict resolved build is green |
@dotnet-bot test Windows_NT x64 Checked corefx_baseline |
@jkotas build is green |
@AviAvni Thank you for your persistence in pushing this through! |
@jkotas thank you and the team very much for helping me I'll follow if there is more things from me |
Hiii @jkotas I'm working on the Roslyn PR and testing with .net core sdk preview 6 |
@AviAvni Thank you! If you won't be able to get to this soon, could you please at least file an issue in CoreCLR repo so that we have it tracked? |
dotnet/roslyn#953
Succesfully compile and run https://gist.github.com/AviAvni/00831abbddf4ceca198236de362ed449