-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Support Delegate and MulticastDelegate as generic type constraints #24443
Support Delegate and MulticastDelegate as generic type constraints #24443
Conversation
SymbolDisplayPartKind.NamespaceName, | ||
SymbolDisplayPartKind.Punctuation, | ||
SymbolDisplayPartKind.ClassName); | ||
} |
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.
Consider tests that check the display string for the containing type for each of these cases, using new SymbolDisplayFormat(genericOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints)
. #Resolved
Dim c = new Test(Of string)() ' reference type | ||
~~~~~~ | ||
</expected>) | ||
End Sub |
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.
Consider testing New Test(Of Delegate)
and New Test(Of MulticastDelegate)
in each case. #Resolved
Sorry if i missed it. But has a reason been given to not use the more C#-keywordy-centric form:
It seems like those would make much more sense from a syntactic perspective for users as those are already the existing keywords needed to describe a delegate/enum today. For example, users don't say: struct S : System.Enum { } They say: In no other parts of the language have we generally exposed these concepts through System.Enum or System.Delegate/MulticastDelegate. So it seems odd to use the fully qualified names here in constraints when we already have keywords. #ByDesign |
// (15,30): error CS0311: The type 'System.Delegate' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.Delegate' to 'D1'. | ||
// var d = new Test<D1, System.Delegate>(); | ||
Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test<T, U>", "D1", "U", "System.Delegate").WithLocation(15, 30)); | ||
} |
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.
} [](start = 8, length = 1)
Consider testing Test<Delegate, MulticastDelegate>
, Test<MulticastDelegate, Delegate>
, Test<MulticastDelegate, MulticastDelegate>
. #Resolved
// (15,30): error CS0311: The type 'System.MulticastDelegate' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.MulticastDelegate' to 'D1'. | ||
// var d = new Test<D1, System.MulticastDelegate>(); | ||
Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.MulticastDelegate").WithArguments("Test<T, U>", "D1", "U", "System.MulticastDelegate").WithLocation(15, 30)); | ||
} |
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.
} [](start = 8, length = 1)
Consider testing Test<Delegate, Delegate>
, Test<Delegate, MulticastDelegate>
, Test<MulticastDelegate, Delegate>
. #Resolved
CompileAndVerify(code, expectedOutput: @" | ||
Got 2 and 3 | ||
Got 7 and 9"); | ||
} |
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.
} [](start = 8, length = 1)
Consider testing:
class A1<T> where T : Delegate { }
class B1<T> : A1<T> where T : MulticastDelegate { }
class A2<T> where T : MulticastDelegate { }
class B2<T> : A2<T> where T : Delegate { }
``` #Resolved
@CyrusNajmabadi I believe the reason is that this is not a main scenario, and it was not worth it to do changes to the parser/language rules to enable this. This change aims at doing the least amount of work possible to unblock people from using a feature that roslyn already supports (we import and can use such generics, we just don't allow them in source). In reply to: 360571323 [](ancestors = 360571323) |
IMO, while 'least amount of work' is nice from a prototyping standpoint, it's not great from an actual language design standpoint. This new language doesn't feel (to me) like how i would think C# should expose this sort of functionality. For example, the
The parser changes seem fairly trivial. I would just allow "enum/delegate" and make appropriate constraint nodes for them. Am i missing something in terms of how hard that would be. It seems tiny.
If we're not willing to update the language rules to allow for this in such a tiny manner... i'm wondering why we're allowing htis at all :D |
Don't you just need to change ParseTypeParameterConstraint into: case SyntaxKind.StructKeyword:
var structToken = this.EatToken();
return _syntaxFactory.ClassOrStructConstraint(SyntaxKind.StructConstraint, structToken);
case SyntaxKind.ClassKeyword:
var classToken = this.EatToken();
return _syntaxFactory.ClassOrStructConstraint(SyntaxKind.ClassConstraint, classToken);
case SyntaxKind.EnumKeyword:
var classToken = this.EatToken();
return _syntaxFactory.EnumConstraint(classToken);
case SyntaxKind.DelegateKeyword:
var classToken = this.EatToken();
return _syntaxFactory.DelegateConstraint(classToken); ? |
Not just allowing it in the
The reason is to unblock the small portion of users that would use these constraints, but otherwise cannot. My two cents based on initial discussions, the proposal comments, and design meetings, is that not a lot of people would require using a I'm not saying it is impossible, I'm just saying it is a much bigger scope than the design plan (lifting one artificial compiler error that we didn't need, and add appropriate tests). Adding additional syntax because it looks nicer is an extra goal that will add a small value to a small percentage of users. |
I agree on that. However, |
I'll do the IDE work :). AFAICT, the only impact would be on completion, symbol display and a bit of the code-gen infrastructure. All would be quite trivial. |
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.
LGTM
@CyrusNajmabadi another consideration is also we can think in the future of providing enum constraints to a specific type, like |
@dotnet/roslyn-ide can I get a code review? I added a few IDE tests, no source changes. |
That depends :) Is this just temp/prototype work you're doing? Or is this intended to be checked into the compiler and become part of the language proper for all time? If the latter, then i would just want the LDM to sign off on this being the way they want the concept exposed. If LDM is fine, then no objections by me. If LDM thinks keyword-syntax is appropriate, then i think that should be done. |
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.
IDE side changes look fine. My signoff obviously doesn't count for the rest of it. 😄
@CyrusNajmabadi Type syntax is already approved by LDM for C# 7.3, keyword syntax is still TBD. |
Awesome. Thanks! |
Enables using
System.Delegate
andSystem.MulticastDelegate
as constraints for generic parameters.Example:
Roslyn Proposal: #158
Corefx Proposal: dotnet/csharplang#86
Champion Issue: dotnet/csharplang#103
@dotnet/roslyn-compiler @dotnet/roslyn-ide @VSadov for review