Skip to content

Test plan for "records" #40726

@jcouv

Description

@jcouv

Relates to championed issue: dotnet/csharplang#39
Spec: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md
Records board: https://github.com/dotnet/roslyn/projects/57

LDM:

  • ToString: should we always print a trailing comma R { Property1 = 42, Property2 = 43, }? (no)
  • ToString: can we deal with stack overflow potential? (do nothing special for now)
  • ToString: should we try to quote/escape values, for example R { IntProperty = 42, StringProperty = "hello" }? (no)
  • ToString: should we omit ToString on abstract records? (no)
  • ToString: should PrintMembers call ToString() on values to avoid boxing them in builder.Append((object)value)? (yes)
  • ToString: should we try and avoid the double space in empty record R { }? (yes)
  • ToString: do we want to economize a call to StringBuilder.Append to print <name> { ? (maybe)
  • warn on declaring type named "record" in C# 9? (yes)
  • Can we omit EqualityContract if the record type is sealed and derives from System.Object? (no)
  • Should we allow base syntax on record without parameter list? record Derived : Base(0) { } (yes)
  • nullability expectations for bool Equals(R? other) and Type EqualityContract { get; } and R? <Clone>$() and void Deconstruct(out string? NotNullableStringProperty). (issue Records: Incorrect nullable annotations for generated Equals override #47627)
  • Ensure spec forbids an empty parameter list.
  • LDM: How to give base ctor arguments if there are no record parameters
  • Should records have a base type that isn't object? (no)
  • Allow with on non-record types (maybe with user-defined Clone() method)? (out of scope for C# 9)
  • Confirm syntax model for data properties (out of scope for C# 9)
  • Constraint for with-able? Allows t with { ... } with use of : where T : I, with (like we could do : where T : I, new)? (out of scope for C# 9)
  • Should anonymous objects be with-able? (out of scope for C# 9)
  • bringing structs closer to ideal value semantics (out of scope for C# 9)
  • .ToString() (yes)
  • xml docs (issue Figure out XML docs for positional records #44571, support params for now)
  • Should we allow record Base { public int P => 0; } record Derived(int P); and how does it work? (maybe Derived gets new int P { get; init; }, or maybe it's an error)
  • allow deriving from non-record types? (not in C# 9)
  • tagging record types (supports MetadataAsSource scenario, using unspeakable clone method for now)
  • confirm data vs. record syntax (record Person(...) for next preview)
  • init-only: should _ = new C() { readonlyField = null }; be allowed in a method on type C? (comment) (punted out of C# 9)
  • init-only: confirm metadata encoding (modreq?) and rules for dealing with ambiguous IsExternalInit type (confirmed)
  • init-only methods ? init void Init() (punted out of C# 9, strong interest, issue with Add methods in BCL immutable collection types)
  • with initializer with expressions allowed in other kinds of initializers, such as [0] = 2 or values for IEnumerable/Add collection. (punted out of C# 9)

Record declarations

Compiler:

  • Block or handle EnC (Support EnC on records and with expressions #44877)
  • xml docs (params should apply to primary constructor parameters) (Figure out XML docs for positional records #44571)
  • LangVer diagnostic quality (Record syntax in LangVer=8 should not complain about top-level statement #45900)
  • nullability analysis: warn on bad user-provided methods (issue Records: Incorrect nullable annotations for generated Equals override #47627)
  • nullability analysis: set property state based on constructor arguments (Record constructor arguments should propagate nullability to properties #44763)
  • probably need some public APIs for detecting record, identifying primary constructor and mapping parameters with properties
  • operator== (Records should generate operator == and != #46381)
  • ToString (Records should generate ToString #46382)
  • attributes on record parameters targeted to parameter (default) or field or property
  • parsing with different LangVersions (and document breaking change)
  • Disallow declaring members with name "Clone"
  • parsing of record is conditional on LangVersion ("preview" now and "9" later)
    • abstract record M(int i, int j); (parses differently based on LangVersion)
    • bool record; (remains a field or local, regardless of LangVersion)
  • Clone extension method allowed? (no)
  • Clone with params or optional parameters? (no)
  • record with custom copy constructor
  • out vars in with initializer (verifies scoping and execution order)
  • two copy constructors, one is correct and the other adds params or optional parameter
  • verify sequence points
  • default values on positional members (data class Person(string Name = null, decimal height = 0) { })
  • test type named "@record" (see TypeNamedRecord_*)
  • generic or retargeted records
  • can positional partial record reiterate its base without providing arguments Bind base arguments fo records #44876 (comment)
  • Inherit from a record containing sealed override <>Clone
  • record C(Property int) { public int Property { set { } } } (no getter in user-defined property)
  • test IOperation on record base
  • test covering user-defined copy ctor without initializer and synthesized copy ctor when System.Object lacks parameter-less constructor.
  • test synthesized copy ctor where base copy ctor produces use-site diagnostic (comment) or has unsupported metadata (comment)
  • Test caller line number supplied by compiler constructor initialiser based on base arguments (see LocalRewriter.GetCallerLocation, see AttributesOnPrimaryConstructorParameters_09_CallerMemberName)
  • Test implementation of SyntaxExtensions.IsInContextWhichNeedsDynamicAttribute in relation to PrimaryConstructorBaseType
  • Test implementation of SyntaxFacts.IsInTypeOnlyContext and SyntaxFacts.IsNamedArgumentName in relation to PrimaryConstructorBaseType
  • Test nullability analysis within base arguments.
  • attributes on record (AttributesOnPrimaryConstructorParameters_*)
  • modifiers followed by partial (PartialTypes_04_PartialBeforeModifiers)
  • only one partial declaration can have the parameter list (PartialTypes_01, missing from SPEC)
  • Can't provide Equals(Base) in source (BaseEquals_05)
  • Can't provide Equals(object) in source (ObjectEquals_06)
  • scope of positional parameters
  • Verify that field initializers on 'partial' records can access primary constructor parameters, even if the lexically containing partial declaration doesn't include a parameter list (see PartialRecord_ParametersInScopeOfBothParts)
  • ping F# team for records design
  • Deconstruct and deconstruct (see Deconstruct_*)
  • record nested in generic type (see RecordInsideGenericType)
  • Fix 'error CS8850: A positional record must have both a 'data' modifier and non-empty parameter list' message
  • spec: Explaining what is a "record" type (ie. has a clone method)
  • record synthesized property can implement interface (see InterfaceImplementation)

Productivity:

with expressions

  • ref safe-to-escape
  • disallow as expression-statement (Fix parsing of with-expression directly inside expression statement #44688)
  • semantic model on with expression (get the Clone() method)
  • with on a ref local
  • GetSymbolInfo on the properties inside a with (see WithExpr28_WithAwait)
  • data flow in with (see TestWithExpression)
  • with on TRecord (fixed)
  • _ = tRecordAndInterface with { /* try to set interface members */ }; (fixed)
  • with expression on dynamic type (disallow, see WithExpr24_Dynamic)
  • should Obsolete on record type carry over to synthesized methods? (no)
  • test in exception filter (see WithExpr27_InExceptionFilter)
  • await inside a with (see WithExpr28_WithAwait)
  • test new Person() with { First = null, First = null } (WithExpr_NullableAnalysis_*)
  • should we consider going even one step further and parsing with initializers with kind = ObjectInitializerExpression instead of WithInitializerExpression? (done)
  • OperationCloner and CFG should support with expressions (added IWithOperation)
  • block with in expression trees (TestInExpressionTree)
  • IOperation/CFG for with expression (PR)

init only

Speclet: https://github.com/dotnet/csharplang/blob/master/proposals/init.md

Productivity:

API:

  • Confirm behavior of IsInitOnly on static int Property { init { } }
  • Confirm name of API (IsInitOnly) and feature in spec

data properties (out of scope for C# 9)

  • Test that analyzer events are created/received for the symbol and the initializer pieces
  • IOperation test for the initializer
  • allow sealed modifier (LDM 7/6/2020)

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done Umbrellas

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions