Support SetsRequiredMembersAttribute#60392
Support SetsRequiredMembersAttribute#60392333fred merged 14 commits intodotnet:features/required-membersfrom
Conversation
|
@RikkiGibson @jcouv please take a look. |
The SetsRequiredMembersAttribute prevents the compiler from checking the required member list of a type when calling that constructor, and suppresses any errors from a base type's list being invalid. Specification: https://github.com/dotnet/csharplang/blob/main/proposals/required-members.md Test plan: dotnet#57046
3d01290 to
7761d6b
Compare
|
@jcouv @RikkiGibson please take a look |
RikkiGibson
left a comment
There was a problem hiding this comment.
Just had a few comments so far. Haven't looked at the tests yet--possible those will hold answers to some of the questions anyway. Will review the tests a little later this afternoon.
src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs
Show resolved
Hide resolved
|
@RikkiGibson @jcouv please take a look. |
RikkiGibson
left a comment
There was a problem hiding this comment.
LGTM aside from some minor comments.
|
@jcouv for the second review please. |
src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs
Show resolved
Hide resolved
jcouv
left a comment
There was a problem hiding this comment.
Done with review pass (iteration 7)
|
Just curious, what was the problem you ran into that the used assemblies leg detected? In reply to: 1083559918 |
d9da29b. It wasn't happy about mismatched collection of dependencies. |
…operties should be considered initialized.
|
@RikkiGibson @jcouv please take another look. |
src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs
Outdated
Show resolved
Hide resolved
|
I was contemplating whether it's reasonable for constructors to delegate to 'SetRequiredMembers' constructors, without being 'SetsRequiredMembers' themselves. For example, test class Base
{
public required string Prop1 { get; set; }
[SetsRequiredMembers]
public Base() { Prop1 = "a"; }
public Base(int unused) { }
}
class Derived : Base
{
public required string Prop2 { get; set; }
// maybe compiler needs to emit [SetsRequiredMembersOf(typeof(Base))] here?
public Derived() : base() { }
// maybe compiler needs to emit [SetsRequiredMembersOf(typeof(Base))] here?
public Derived(int unused) : this() { }
}
class Program
{
static void Main()
{
// how do we realize the user doesn't need to set Prop1?
var derived = new Derived() { Prop2 = "a" };
// we seem even more at sea here :)
var derived2 = new Derived(1) { Prop2 = "a" };
}
}The metadata encoding spec doesn't appear to be able to represent this as written. Did I miss something? I could imagine complex type hierarchies peppering in 'SetsRequiredMembers' at arbitrary levels. It feels like representing that accurately would require tracking the most-derived type in the hierarchy which has the attribute. When the compiler binds a constructor it can determine which base constructor it ultimately delegates to, perhaps using a similar mechanism as is currently used to prevent cycles in constructor initializers. However, it feels to me like it would be a very reasonable starting place to require any constructors which delegate to a 'SetsRequiredMembers' constructor to also have 'SetsRequiredMembers'. This would make it an all-or-nothing thing down the hierarchy to start with, and I think it leaves the space open for us to add something like what I described above later on. |
|
@RikkiGibson we could do that. My initial thought was, however, not to do any form of restrictions. In short, in your example, there is no way to know that |
…o setsrequiredmembers * upstream/features/required-members: (808 commits) Update for definite assignment changes Remove duplicate package references (dotnet#60658) Formatting and code generation options (dotnet#60127) Trim unnessasary leading lines when removing usings (dotnet#60672) Pass options to FixAllAsync, simplify CodeAction registration (dotnet#60665) Fallout Lint Restore CodeStyle test projects Update struct field definite assignment tests Global indentation options - take 2 (dotnet#60565) Run continuation to dispose of cancellation token source (dotnet#60653) Fixup Update tests Cleanup Cleanup move properties Delay starting the work to scan for todo-items Simplify Clean up syntax context Clean up syntax context ...
…n chaining to a constructor with the attribute. Add more tests.
|
@RikkiGibson @jcouv please take another look. |
…o setsrequiredmembers * upstream/features/required-members: (66 commits) Fix dotnet#55183: Add SymbolVisitor<TArgument, TResult> (dotnet#56530) Simplifier options (dotnet#60174) Remove duplicated asset Do not try to refcount solution syncing when communicating with OOP Delay symbol-search index updating until solution is fully loaded. add more miscellaneous tests for checked operators (dotnet#60727) Support checked operators in explicit interface implementation (dotnet#60715) Avoid formatting diagnostics with raw strings (dotnet#60655) Make heading levels for warning waves documentation consistent (dotnet#60721) Clean up IDiagnosticService extension methods Remove #nullable enable Add integration test to flag MEF composition breaks Generate static abstract interface members correctly (dotnet#60618) Merge release/dev17.2 to main (dotnet#60682) Fix FAR on checked operators (dotnet#60698) Add implement interface support for checked operators and cast operators (dotnet#60719) Update csc.dll path in launch.json (dotnet#60663) Grab bag of UTF8 string support in IDE features (dotnet#60599) Allow code actions to retrieve options for any language (dotnet#60697) Fix flaky VSTypeScriptHandlerTests (dotnet#60706) ...
| } | ||
| else if (initializerKind == (int)SyntaxKind.BaseConstructorInitializer) | ||
| { | ||
| // If we chained to a `base` constructor, a SetsRequiredMembers attribute applies to the base type's required members only, and the current type's required members |
There was a problem hiding this comment.
It seems like the code paths which handle SetsRequiredMembers on base but not this could be eliminated.
There was a problem hiding this comment.
I'm not sure what you mean by this? Can you elaborate?
There was a problem hiding this comment.
I was wrong about this. I recall now that you're still expected to get a different initial state when the 'this()' constructor you chain to has SetsRequiredMembers, versus the 'base()' constructor you chain to having it.
For some reason I expected a further simplification in NullableWalker to fall out of the decision to require SetsRequiredMembers to be used on constructors which chaining to a SetsRequiredMembers constructor.
RikkiGibson
left a comment
There was a problem hiding this comment.
LGTM with one comment which can be addressed in a subsequent PR if you prefer.
The SetsRequiredMembersAttribute prevents the compiler from checking the required member list of a type when calling that constructor, and suppresses any errors from a base type's list being invalid.
Specification: https://github.com/dotnet/csharplang/blob/main/proposals/required-members.md
Test plan: #57046