Skip to content
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

Report error for T? when T is unconstrained #28804

Merged
merged 13 commits into from
Jul 27, 2018

Conversation

cston
Copy link
Member

@cston cston commented Jul 24, 2018

No description provided.

@cston cston requested a review from a team as a code owner July 24, 2018 05:16
@@ -5363,6 +5363,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_ExplicitNullableAttribute" xml:space="preserve">
<value>Explicit application of 'System.Runtime.CompilerServices.NullableAttribute' is not allowed.</value>
</data>
<data name="ERR_NullableUnconstrainedTypeParameter" xml:space="preserve">
<value>A nullable type parameter must have a value type or reference type constraint.</value>
Copy link
Member

@jcouv jcouv Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider something more specific to guide users:
"... must be known to be a value or reference type. Consider adding a class, struct or type constraint." #Closed

public static TypeSymbol VisitType<T>(
this TypeSymbolWithAnnotations type,
Func<TypeSymbolWithAnnotations, T, bool, bool> predicate1,
Func<TypeSymbol, T, bool, bool> predicate2,
Copy link
Member

@jcouv jcouv Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we find better named than predicate1 and predicate2? #Closed

// The first unconstrained type parameter in the type.
var typeParameter = this.VisitType(
(t, a, b) => t.IsAnnotated && t.TypeSymbol.IsUnconstrainedTypeParameter(),
(t, a, b) => false,
Copy link
Member

@jcouv jcouv Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the parameters have more meaningful names. Please use named arguments here. #Closed

}

private static TypeSymbol VisitType<T>(
TypeSymbolWithAnnotations typeWithAnnotationsOpt,
Copy link
Member

@jaredpar jaredpar Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prototype comment to address once TWA is a struct? #Closed

@@ -333,6 +333,15 @@ public bool GetUnificationUseSiteDiagnosticRecursive(ref DiagnosticInfo result,

public void CheckAllConstraints(ConversionsBase conversions, Location location, DiagnosticBag diagnostics)
{
// The first unconstrained type parameter in the type.
var typeParameter = this.VisitType(
Copy link
Member Author

@cston cston Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This code path only handles a fraction of the cases where T? can appear. (See failing tests.) The diagnostic probably needs to be reported elsewhere. #Resolved

@jcouv jcouv self-assigned this Jul 24, 2018
@333fred
Copy link
Member

333fred commented Jul 24, 2018

@cston test failures appear legitimate. #Closed

@cston
Copy link
Member Author

cston commented Jul 26, 2018

@dotnet/roslyn-compiler please review. #Closed

@@ -395,6 +395,8 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r
DeclaringCompilation.SynthesizeTupleNamesAttribute(type.TypeSymbol));
}

// PROTOTYPE(NullableReferenceTypes): type.ReportAnnotatedUnconstrainedTypeParameterIfAny()
Copy link
Member

@333fred 333fred Jul 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we do this today? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to do these today, but these were cases where we may need to pass through a DiagnosticBag. It seemed more important to get the general approach for now rather than covering all the corner cases.


In reply to: 205633140 [](ancestors = 205633140)

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM other than the question on the prototype comment additions.

@cston
Copy link
Member Author

cston commented Jul 27, 2018

@jcouv, please review, thanks. #Closed

/// traversal stops and that type is returned from this method. Otherwise if traversal
/// completes without the predicate returning true for any type, this method returns null.
/// </summary>
public static TypeSymbol VisitType<T>(
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This signature, with two exclusive parameters, seems strange. Could we have one VisitType for TypeSymbol and one for TypeSymbolWithAnnotations?
Both would receive both predicates, and they would be mutually recursive (the overload for TSWA is a trivial wrapper for the other overload).

Alternatively, would it help to bundle the TypeSymbol and TSWA for this API? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One predicate is not sufficient in two cases: when the top-level type is a TypeSymbol rather than TypeSymbolWithAnnotations, and when walking up the containing types which are also TypeSymbols.


In reply to: 205834509 [](ancestors = 205834509)

Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't mean bundle the predicates (I understand we need to keep two). I meant the TypeSymbol typeOpt and TSWA ... parameters. #Closed

Copy link
Member Author

@cston cston Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it's strange to have two mutually exclusive parameters. But it does allow writing specific helper methods that encapsulate the call to VisitType but that also take either a TypeSymbol or a TypeSymbolWithAnnotations (see TypeSymbolWithAnnotations.ContainsNullableReferenceTypes for instance).


In reply to: 205853384 [](ancestors = 205853384)

if (returnType.ContainsAnnotatedUnconstrainedTypeParameter() ||
parameters.Any(p => p.Type.ContainsAnnotatedUnconstrainedTypeParameter()))
{
TypeSymbolWithAnnotations.ReportAnnotatedUnconstrainedTypeParameter(location, _diagnostics);
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReportAnnotatedUnconstrainedTypeParameter [](start = 42, length = 41)

I'm confused. If I read this code correctly, it seems like we're not reporting on the specific location that caused the problem.
Yet, I think this is covered by NullableT_LocalFunction which seems to report a specific diagnostic (either on return type or parameter type).
I don't understand how that works.

Also, it feels strange to report this kind of diagnostic (for lambdas and local functions) during lowering. Could the check be moved into the relevant symbols? #Closed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at LocalFunctionSymbol, I see that the check is performed there. That's why the NullableT_LocalFunction test works.
Then I wonder which scenarios/tests hit this code path?


In reply to: 205838678 [](ancestors = 205838678)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Removed.


In reply to: 205839676 [](ancestors = 205839676,205838678)

if (parameter.Type.ContainsNullableReferenceTypes())
var location = parameter.GetNonNullSyntaxNode().Location;
var parameterType = parameter.Type;
parameterType.ReportAnnotatedUnconstrainedTypeParameterIfAny(location, diagnostics);
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReportAnnotatedUnconstrainedTypeParameterIfAny [](start = 30, length = 46)

I understand the appeal of bundling this check here (paired with check for existence of Nullable attribute, as in other places). Maybe the method should be renamed to reflect that.
Maybe CheckParametersForNullability? (or some better name)

Or maybe create a new method ParameterHelpersReportAnnotatedUnconstrainedTypeParameters? #Resolved

@@ -303,26 +303,24 @@ internal override LexicalSortKey GetLexicalSortKey()

internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics)
{
Location getReturnTypeLocation()
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getReturnTypeLocation() [](start = 25, length = 23)

Not related to this PR: Any idea why we were doing those gymnastics before? Seems really strange. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the local functions in #22820 to allow the locations to be calculated late without duplicating code in each place that needed a location.


In reply to: 205842705 [](ancestors = 205842705)

{
this.DeclaringCompilation.EnsureNullableAttributeExists(diagnostics, Locations[0], modifyCompilation: true);
TypeSymbolWithAnnotations.ReportAnnotatedUnconstrainedTypeParameter(location, diagnostics);
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we report more specific locations here too? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment.


In reply to: 205843155 [](ancestors = 205843155)

Func<TypeSymbolWithAnnotations, T, bool, bool> typeWithAnnotationsPredicateOpt,
Func<TypeSymbol, T, bool, bool> typePredicateOpt,
T arg,
bool canDigThroughNullable = false)
{
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ [](start = 8, length = 1)

Consider asserting that we must have a Type or a TSWA, but not both. #Closed

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done with review pass (iteration 10).

}
ParameterHelpers.ReportAnnotatedUnconstrainedTypeParameters(Parameters, diagnostics);
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReportAnnotatedUnconstrainedTypeParameters [](start = 29, length = 42)

Is the operator case covered by test? #Resolved

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a PROTOTYPE comment to cover


In reply to: 205892348 [](ancestors = 205892348)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The operator case is covered by NullableT_Members. I've added a constructor case to that test.


In reply to: 205909782 [](ancestors = 205909782,205892348)

T arg,
bool canDigThroughNullable = false)
{
Debug.Assert(((object)typeWithAnnotationsOpt == null) != ((object)typeOpt == null));
Copy link
Member

@jcouv jcouv Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

== [](start = 57, length = 2)

nit: could be simplified with is null #Resolved

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Thanks (iteration 12).

@cston cston merged commit 4945499 into dotnet:features/NullableReferenceTypes Jul 27, 2018
@cston cston deleted the nullable-t branch July 27, 2018 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants