# C# Language Design Notes for Apr 25, 2018

***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***

## Agenda


# Warn on nullable ref type argument when T has `class` constraint

``` c#
static void F<T>(T t) where T : class { t.ToString(); /* no warning */ }
F(maybeNull); // warning: string? does not satisfy 'class' constraint
F<string?>(string.Empty); // warning: string? does not satisfy 'class' constraint
```

This is a real danger, and we should be warning here.

Note that in both cases the warning is about constraint checking: even in the second line we infer `string?` and it warns on constraint check.

We should probably have the error message say that this is because of nullability.


# Warn on nullable reference type argument when T has non-nullable reference type or interface type constraint

``` c#
static void F<T>(T t) where T : IDisposable { }
F(maybeNull); // warning: Stream? does not satisfy 'IDisposable' constraint
```
Yes, warn for same reasons.

We also want to warn (or error) on inconsistent nullability in constraints. Specifically if one constraint is known to be non-nullable and another is known to be nullable.

What about

``` c#
class C<T, U, V> where T: class? where U : T, IDisposable where V : T, IDisposable?
{
    // Fine
}
class D<T, U, V> where T: class where U : T, IDisposable where V : T, IDisposable?
{
    // Warn on V
}
```

``` c#
... where T : Node<T>?
... where T : Node<T?> // both currently allowed, but not where T : Node<T?>?
... where T : class, INode<T?>
... where T : class?, INode<T>?
```

``` c#
static void F<T>(T t) where T : IFoo<string?> { }
IFoo<string> foo;
F(foo); // warning, unless IFoo is covariant
```

Another kind of clash:

``` c#
interface IBar : IFoo<string> {}
static void F<T>(T t) where T : IFoo<string?>, IBar { }
```

We want to warn on this: maybe find shared base interfaces between the two constraints, and check if they have consistent nullability.

Other, slightly more complex example, same conclusion: 
``` c#
interface IBar : IFoo<string?> {}
static void F<T, U>(T t) where T : IFoo<U>, IBar where U : class{ }
```


# Allow nullable reference types and interface types as constraints 

`where T : Person?, IDisposable?`

Yes

# Allow `class?` constraint

Yes

How do we express in metadata?

Let's put top-level nullability as an attribute on the type parameter itself, rather than on the constraints. We can noodle more on this later.

# Allow `object` constraint

``` c#
static void F<T>(T t) where T : object { }
F(maybeNull); // warning: constraint violated
```

## Need to talk about relationship to value types soon

``` c#
int? i = null;
object o = i;
o.ToString();
```

# Allow `object?` explicitly?

It's the "most general" constraint that is implied by unconstrained generics. Today we disallow `object` because of that. 

We don't know that this is a terribly useful restriction today, but we'll keep doing it (now with `object?`) unless we get evidence to the contrary.


# Warn on dereference of T when T is unconstrained?

Yes, if a type parameter `T` can be instantiated with a nullable reference type, then we should track null state and warn on unguarded dereference.

The warning when occurring on unconstrained generics might suggest using the `object` constraint.


# Warn on assignment to `object` of unconstrained `T`?

Yes. This can be a `W` (cosmetic) warning when the `object` variable is a local.


# default(T) with unconstrained T

``` c#
T M<T>()
{
    T t = default(T); // W warning
    return default(T); // safety warning
}
```

This is something completely safe. I don't want it to warn!:

``` c#
T M<T>()
{
    var t = default(T);
    if (something) t = somethingelse;
    if (t != null) WriteLine(t.ToString());
}
```

This could be an argument for allowing `T?` that is not about special methods. Or it is an argument against having the W warnings at all.

Let's keep this example around and revisit. But for now, let's consider `default(T)` to be potentially null, and therefore warn on its unguarded use.


# Annotations

We would like to deal with methods with special null semantics, such as string.IsNullOrEmpty, TryGetValue, Assert.NotNull, Object.Equals, Object.ReferenceEquals.

We'll come back to this later.
