Addressed pr feedback.

上级 962daf5e
......@@ -163,6 +163,8 @@ protected override void Free()
}
}
// PROTOTYPE(NullableReferenceTypes): Investigate remaining IsReferenceType usage for replacement by !IsValueType if necessary.
protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException()
{
return true;
......@@ -319,10 +321,12 @@ private void Populate(ref LocalState state, int start)
}
// PROTOTYPE(NullableReferenceTypes): Consider setting treatUnconstrainedTypeParameterAsNullable during initial binding, and removing this method.
private static TypeSymbolWithAnnotations GetAdjustedType(TypeSymbolWithAnnotations? initialType)
/// <summary>
/// Adjust the given type, treating unconstrained type parameters as nullable if in the appropriate context. This overrides the current state
/// of type parameter.
/// </summary>
private static TypeSymbolWithAnnotations UnconstrainedTypeParametersAsNullable(TypeSymbolWithAnnotations? initialType)
{
// If the initial type was an unconstrained type parameter, we want to treat it as nullable, overriding
// the annotated state.
if (initialType is null || initialType.Value.IsNull)
{
return default;
......@@ -776,15 +780,16 @@ private void EnterParameters()
for (int i = 0; i < n; i++)
{
var parameter = methodParameters[i];
var parameterType = signatureParameters[i].Type;
_variableTypes[parameter] = GetAdjustedType(parameterType);
var parameterType = UnconstrainedTypeParametersAsNullable(signatureParameters[i].Type);
EnterParameter(parameter, parameterType);
}
}
private void EnterParameter(ParameterSymbol parameter, TypeSymbolWithAnnotations parameterType)
{
_variableTypes[parameter] = parameterType;
int slot = GetOrCreateSlot(parameter);
Debug.Assert(!IsConditionalState);
if (slot > 0 && parameter.RefKind != RefKind.Out)
{
......@@ -928,13 +933,14 @@ private TypeSymbolWithAnnotations GetReturnType()
{
var method = (MethodSymbol)_member;
var returnType = (_useMethodSignatureReturnType ? _methodSignatureOpt : method).ReturnType;
returnType = GetAdjustedType(returnType);
returnType = UnconstrainedTypeParametersAsNullable(returnType);
Debug.Assert((object)returnType != LambdaSymbol.ReturnTypeIsBeingInferred);
return method.IsGenericTaskReturningAsync(compilation) ?
((NamedTypeSymbol)returnType.TypeSymbol).TypeArgumentsNoUseSiteDiagnostics.Single() :
returnType;
}
// Consider making these local functions.
private static bool IsNullable(TypeSymbolWithAnnotations typeOpt)
{
return !typeOpt.IsNull && typeOpt.IsNullable == true;
......@@ -986,7 +992,7 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node)
(initializer, conversion) = RemoveConversion(initializer, includeExplicitConversions: false);
TypeSymbolWithAnnotations valueType = VisitRvalueWithResult(initializer);
TypeSymbolWithAnnotations type = GetAdjustedType(local.Type);
TypeSymbolWithAnnotations type = UnconstrainedTypeParametersAsNullable(local.Type);
if (node.DeclaredType.InferredType)
{
......@@ -1895,7 +1901,7 @@ public override BoundNode VisitCall(BoundCall node)
//if (this.State.Reachable) // PROTOTYPE(NullableReferenceTypes): Consider reachability?
{
_resultType = GetAdjustedType(method.ReturnType);
_resultType = UnconstrainedTypeParametersAsNullable(method.ReturnType);
}
return null;
......@@ -2777,7 +2783,7 @@ public override BoundNode VisitConversion(BoundConversion node)
Visit(operand);
TypeSymbolWithAnnotations operandType = _resultType;
TypeSymbolWithAnnotations explicitType = GetAdjustedType(node.ConversionGroupOpt?.ExplicitType);
TypeSymbolWithAnnotations explicitType = UnconstrainedTypeParametersAsNullable(node.ConversionGroupOpt?.ExplicitType);
bool fromExplicitCast = !explicitType.IsNull;
TypeSymbolWithAnnotations resultType = ApplyConversion(node, operand, conversion, explicitType.TypeSymbol ?? node.Type, operandType, checkConversion: !fromExplicitCast, fromExplicitCast: fromExplicitCast, out bool _);
......@@ -3480,13 +3486,14 @@ private TypeSymbolWithAnnotations GetDeclaredLocalResult(LocalSymbol local)
return _variableTypes.TryGetValue(local, out TypeSymbolWithAnnotations type) ?
type :
local.Type;
//UnconstrainedTypeParametersAsNullable(local.Type);
}
private TypeSymbolWithAnnotations GetDeclaredParameterResult(ParameterSymbol parameter)
{
return _variableTypes.TryGetValue(parameter, out TypeSymbolWithAnnotations type) ?
type :
GetAdjustedType(parameter.Type);
UnconstrainedTypeParametersAsNullable(parameter.Type);
}
public override BoundNode VisitBaseReference(BoundBaseReference node)
......
......@@ -209,12 +209,18 @@ public static TypeSymbolWithAnnotations Create(TypeSymbol typeSymbol, INonNullTy
if ((!isAnnotated && typeSymbol is TypeParameterSymbol) ||
(isAnnotated && typeSymbol.IsReferenceType && !typeSymbol.IsNullableType()))
{
// T (leave unannotated)
// string? (leave annotated)
Debug.Assert(!typeSymbol.IsNullableType());
}
else
{
// PROTOTYPE(NullableReferenceTypes): Investigate whether we can bind unconstrained type
// parameters as annotated during initial binding without causing cycles.
// Initial binding leaves unconstrained type parameters unannotated, NullableWalker will
// set treatUnconstrainedTypeParametersAsNullable where appropriate
// T (leave unannotated when treatUnconstrainedTypeParamersAsNullable is false)
// T (add annotation when treatUnconstrainedTypeParameterAsNullable is true)
// T? where T : class (leave annotated)
// string, int (leave unannotated)
// int?, T? where T : struct (add annotation)
......
......@@ -21123,6 +21123,7 @@ static void F<T>()
var comp = CreateCompilation(
new[] { source, NonNullTypesTrue, NonNullTypesAttributesDefinition },
parseOptions: TestOptions.Regular8);
// PROTOTYPE(NullableReferenceTypes): Improve this diagnostic. default is the cause of the error, but is not mentioned in the diagnostic.
comp.VerifyDiagnostics(
// (5,15): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// T s = default;
......@@ -35863,7 +35864,7 @@ class C3<T3> where T3 : new()
static T3 F3() => new T3();
static void F4()
{
T3 t = (T3)NullableObject(); // warn: return type T4 may be non-null
T3 t = (T3)NullableObject(); // warn: T3 may be non-null
}
}
class C4<T4> where T4 : I
......@@ -35873,7 +35874,7 @@ class C4<T4> where T4 : I
static T4 F2() => default(T4); // warn: return type T4 may be non-null
static void F4()
{
T4 t4 = (T4)NullableObject(); // warn: return type T4 may be non-null
T4 t4 = (T4)NullableObject(); // warn: T4 may be non-null
}
}
class C5<T5> where T5 : A
......@@ -36204,6 +36205,112 @@ public void UnconstrainedTypeParameter_Return_03()
);
}
[Fact]
public void UnconstrainedTypeParameter_Uninitialized()
{
var source =
@"
class C
{
static void F1<T>()
{
T t;
t.ToString(); // 1
}
}
";
var comp = CreateCompilation(new[] { source, NonNullTypesAttributesDefinition, NonNullTypesTrue }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (7,9): error CS0165: Use of unassigned local variable 't'
// t.ToString(); // 1
Diagnostic(ErrorCode.ERR_UseDefViolation, "t").WithArguments("t").WithLocation(7, 9)
);
}
[Fact]
public void UnconstrainedTypeParameter_OutVariable()
{
var source =
@"
class C
{
static void F1<T>(out T t) => t = default; // 1
static void F2<T>(out T t) => t = default(T); // 2
static void F3<T>(T t1, out T t2) => t2 = t1;
static void F4<T, U>(U u, out T t) where U : T => t = u;
static void F5<T, U>(U u, out T t) where T : U => t = (T)u; // 3
static void F6<T, U>(U u, out T t) => t = (T)(object)u; // 4
}
";
// PROTOTYPE(NullableReferenceTypes): there should be a warning for F5
var comp = CreateCompilation(new[] { source, NonNullTypesAttributesDefinition, NonNullTypesTrue }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (4,39): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// static void F1<T>(out T t) => t = default; // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(4, 39),
// (5,39): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// static void F2<T>(out T t) => t = default(T); // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default(T)").WithLocation(5, 39),
// (9,50): warning CS8600: Converting null literal or possible null value to non-nullable type.
// static void F6<T, U>(U u, out T t) => t = (T)(object)u; // 4
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "(object)u").WithLocation(9, 50)
);
}
[Fact]
public void UnconstrainedTypeParameter_PatternMatching()
{
var source =
@"
class C
{
static void F1<T>(object o, T tin)
{
if (o is T t1)
{
t1.ToString();
}
else
{
t1 = default; // 1
}
t1.ToString(); // 2
if (!(o is T t2))
{
t2 = tin;
}
else
{
t2.ToString();
}
t2.ToString(); // 3
if (!(o is T t3)) return;
t3.ToString();
}
}
";
var comp = CreateCompilation(new[] { source, NonNullTypesAttributesDefinition, NonNullTypesTrue }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (12,18): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// t1 = default; // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(12, 18),
// (15,9): warning CS8602: Possible dereference of a null reference.
// t1.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t1").WithLocation(15, 9),
// (25,9): warning CS8602: Possible dereference of a null reference.
// t2.ToString(); // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t2").WithLocation(25, 9)
);
}
// PROTOTYPE(NullableReferenceTypes): Add tests for unconstrained T in foreach and using
[Fact]
public void TypeParameter_Return_01()
{
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册