-
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
Test plan for "target-typed new" #28489
Comments
@jcouv What is the intended behavior for operators? My guess is that for equality, it should behave exactly the same as |
class D {}
class C
{
public static bool operator+(C s, D c);
public static bool operator+(C s, C c);
static void Main()
{
var x = new C() + new(); // error? what if we remove either or both of operators above?
}
}
Note: if we allow this we probably shouldn't infer string or object from string concatenation. |
I agree. The behavior for Looking at the
As a side note, I've updated the proposal for |
Do we want to only permit equality (user-defined and built-in) among comparison and arithmetic operators? |
I don't see a reason to restrict operators, as long as we have a type to target and that type is allowed for target-typed new. This rules out unary operators (no type to target). For types that are disallowed, it would be good to update the proposal to match LDM notes. |
From LDM notes:
With the exception of equality. So I'm thinking that the idea is to follow
To me it's weird because (int a, int b) t = new(1, 2); // "new" is redundant
Action a = new(() => {}); // "new" is redundant
(int a, int b) t = new(); // ruled out by "use of struct default ctor"
Action a = new(); // no constructor found
var x = new() == (1, 2); // ruled out by "use of struct default ctor"
var x = new(1, 2) == (1, 2) // "new" is redundant Can you confirm if this is the intended result?
That might be actually useful (with Exception as the type)? (currently disallowed) |
Thanks for the correction. Then let's restrict on operators (like we do for For tuples, the LDM notes are pretty explicit (ie. allow). We could re-discuss. For Could you make a PR to update the proposal, including those three points (operators, tuples/literals, throw) as open issues? Thanks. Next LDM will be late August. |
Not sure if this is already included, but we'll need to adjust type inferrer here. roslyn/src/Workspaces/CSharp/Portable/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs Line 410 in 1545a96
Probably there's more, because |
Oh. We changed the syntax to make somehting that could previous not be null into someting that can be null? That's definitely concerning. No telling how many things that may break in/out of the roslyn codebase. Any analyzers themselves may be screwed on that. Is compat council ok with that approach? I thought it was a no-no in the past... Any reason this isn't done by introducing something like BaseObjectCreationSyntax, then leaving the existing guy alone (except moving onto that), and then having the new guy derive from that, but have no type-syntax? That way code has to opt into handling this properly. Thoughts? |
Not sure if having a "Base" would help with any scenario (if not breaking). I think we can just follow ImplicitArrayCreation (having ImplicitObjectCreation deriving from Expression). Either way, I agree it's a better approach than just making the field nullable, at least not until we have NRT. |
NRT doesn't even help here. Because that presumes that existing code woudl actually be recompiled to even notice this field could now be null. There may be extensions out there that would not and would simply crash on this.
Introducing a 'Base' form is actually fine. This is what we did with 'foreach' statements when we added support for the deconstruction form: We introduced a CommonForEachStatementSyntax base node and made the existing ForEachStatementSyntax derive from it. We then introduced a new ForEachVariableStatementSyntax for the new form.
This would also be fine with me. |
I'm probably late to this discussion, but why this peculiar "reverse" inference?
I mean, you can see why this looks odd when you place it next to other initializations - most people would naturally expect this:
Why are other variable types inferred from the initialization expression, while for object types instead you declare the type and infer the operand of the new-operator? Is there a practical reason for this inconsistency? |
I'm not seeing the inconsistency. You can already do teh latter form today. This is enabling the former form.
It's unclear why you would do that. If you're using 'var' and 'specifying the type on the right' then i would expect you would continue doing that. |
I'm on latest VS 2019 preview, and I've noticed auto-complete popup doesn't work for new() class initializers. As in:
Is this covered by the test plan? |
Thanks. I must have missed that scenario. Filed #46397 |
But So this isn't currently valid, afaik? class MyClass
{
private var color = new Color("#FFF");
} By consistency, I meant, why can't that just be valid, like it is for inline variables? Why do we need a different syntax to initialize members without repeating the type? |
csharplang
. (https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md)Compiler (general test plan for reference):
TestInLocal_LangVersion8
ArgList
, coversnew(__arglist)
and variants)TestNullableType01
,TestNullableType02
)TestInParameterDefaultValue
), in params (ArrayTypeInferredFromParams
)InAttributeParameter
)InStringInterpolation
)TestInAwait
, no target-type)TestBadTargetType_Cast
)TestInParameterDefaultValue
, not a constant)TestBestType_Lambda
), in async lambda (TestInAsyncLambda_01
)+new()
, ...), equality (1 == new()
), compound (x += new()
), ternary (x ? y : new()
and vice-versa)using
(InUsing01
), innameof()
(InNameOf
), intypeof()
(InTypeOf
), insizeof()
(InSizeOf
), inforeach
(InForeach
), in deconstruction (TestDeconstruction
,var (x, y) = new();
), inswitch
(InSwitch1
), in patterns (InIsOperator
), inif
(ConditionalOnNew
), inwhile
(ConditionalOnNew
), infixed
(InFixed
), as an expression-statement (TestInStatement
,new();
), inlock
(InLock
)InvocationOnDynamic
, no target-type)TestInClassInitializer
)ReturningFromAsyncMethod
)YieldReturn
)var
(TestTargetType_Var
), to nullable type (TestNullableType1
),TestAssignmentToClass
,TestAssignmentToStruct
, TODO currently shows a natural type)new()
andstruct
constraint (TestTypeParameter
,TestTypeParameter_ErrorCases
)new() { 42 }
(TestObjectAndCollectionInitializer
)TestObjectAndCollectionInitializer
,new() { 1, 2, 3 }
)new C() { x = new() }
), collection initializer (new C() { new D(1), new D(2), new() }
) (TestObjectAndCollectionInitializer
)TestTargetType_Enum
), array type, pointer type (TestTargetType_Pointer
, error), test in anonymous type (TestTargetType_AnonymousType
, error), tuple (TestTargetType_TupleType
, okay)RefReturnValue1
,RefReturnValue2
)ImplicitlyTypedArray
, no target-type)TestAssignment
,new() = 1;
)-[ ] test interaction with any C# 8.0 feature that was merged earlier:
??=
(TestInNullCoalescingAssignment
), async-streams, nullability, Ranges (InRange
)IDE:
new()
(SpacingInTargetTypedNew
)(string a, string b)[] ab = new (string a, string b)[1];
vs.C c = new();
new
new()
visible by hovering, when debugging?new()
should go to the proper constructorUseImplicitType
andUseExplicitType
(for example,List<string> list = new();
should never offer to make the declarationvar
)Open LDM questions:
new[]
(Championed: Target-typed implicit array creation expressionnew[]
csharplang#2701 (comment))Initial PR: #25196
Proposal: https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md
Championed issue (with LDM history): dotnet/csharplang#100
Relates to #37821 (spec issues with target-typing)
The text was updated successfully, but these errors were encountered: