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

Improve method type argument inference around tuples and address backwards compatibility break. #22295

Merged
merged 3 commits into from
Sep 26, 2017

Conversation

AlekseyTs
Copy link
Contributor

Fixes #20583.

@dotnet/roslyn-compiler, @VSadov, @jcouv Please review.

@AlekseyTs AlekseyTs added Area-Compilers Language-C# Language-VB New Language Feature - Tuples Tuples Tenet-Compatibility Violation of forwards/backwards compatibility in a design-time piece. labels Sep 22, 2017
@AlekseyTs
Copy link
Contributor Author

CC @jaredpar for approval

@AlekseyTs AlekseyTs requested review from VSadov, jcouv and a team September 22, 2017 18:50
@jaredpar
Copy link
Member

Approved pending signoffs

{
MakeExplicitParameterTypeInferences(binder, (BoundTupleLiteral)argument, target, isExactInference, ref useSiteDiagnostics);
;
Copy link
Member

Choose a reason for hiding this comment

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

; [](start = 16, length = 1)

Please add a comment explaining the control-flow here (perhaps instead of the empty statement)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gafter

Please add a comment explaining the control-flow here (perhaps instead of the empty statement)

Would saying "We were able to do inference from elements of the tuple literal, no need to try to infer from literal's type" be sufficient?

Copy link
Member

Choose a reason for hiding this comment

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

I'd just make it a sequence of separate if statements with returns. Trying to preserve "else if" indeed makes it look strange.


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

Copy link
Member

Choose a reason for hiding this comment

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

@AlekseyTs Yes, that would be a perfect comment to help the reader.

M2((()=>1, ()=>2, ()=>3, ()=>4, ()=>5, ()=>6, ()=>7, ()=>8));
}
public static void M2<T1, T2, T3, T4, T5, T6, T7, T8>(ValueTuple<Func<T1>, Func<T2>, Func<T3>, Func<T4>, Func<T5>, Func<T6>, Func<T7>, ValueTuple<Func<T8>>> a) { Console.Write(2); }
public static void M2<T1, T2, T3, T4, T5, T6, T7, TRest>(ValueTuple<Func<T1>, Func<T2>, Func<T3>, Func<T4>, Func<T5>, Func<T6>, Func<T7>, TRest> a) where TRest : struct { Console.Write(3); }
Copy link
Member

Choose a reason for hiding this comment

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

public [](start = 4, length = 6)

The following test demonstrates that the behavior here is due to a failure to infer type parameters for the second overload. Can you formulate a test in which the tuple does not have a (natural) type, type inference would succeed with both overloads, and the appropriate overload is selected due to the fix? Perhaps one way to do this would be to cast the eighth member of the tuple literal to Func<int>.

Copy link
Contributor Author

@AlekseyTs AlekseyTs Sep 22, 2017

Choose a reason for hiding this comment

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

Can you formulate a test in which the tuple does not have a (natural) type, type inference would succeed with both overloads, and the appropriate overload is selected due to the fix? Perhaps one way to do this would be to cast the eighth member of the tuple literal to Func.

I don't think it is possible given the current language rules. The type for TRest cannot be inferred unless the tuple literal has a natural type, the ValueTupe`1 is never materialized until we are ready to create a type for the entire tuple.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Potentially, we could implement such inference, but it is outside of scope of this PR.

Copy link
Member

Choose a reason for hiding this comment

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

I understand now. Thanks!

@@ -586,7 +586,8 @@ HandleAsAGeneralExpression:
ParameterType,
Parameter,
MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter,
inferenceRestrictions)
inferenceRestrictions,
addedHints:=Nothing)
Copy link
Member

Choose a reason for hiding this comment

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

addedHints [](start = 28, length = 10)

I didn't find where addedHints is used. What is its purpose in the context of this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

What is its purpose in the context of this change? e.g. how it is used to more correctly implement the language feature, if it fixes a bug, and what is the symptom that is fixed? It isn't obvious what the purpose of the change on line 1659 is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gafter The purpose of the logic on line 1659 is to continue with "indirect" inference when direct inference doesn't run into any error conditions and doesn't result in any new hints.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A number of tuple tests were affected by this as well as non-tuple scenario (see ShapeMismatchInOneArgument unit-test in TypeArgumentInference.vb). Before, the indirect inference was performed only when InferTypeArgumentsFromArgumentDirectly was returning false.

@gafter
Copy link
Member

gafter commented Sep 22, 2017

Finished review pass.

@@ -1604,13 +1577,13 @@ private bool ExactConstructedInference(TypeSymbol source, TypeSymbol target, ref
// SPEC: type C<U1...Uk> then an exact inference
// SPEC: is made from each Ui to the corresponding Vi.

var namedSource = source as NamedTypeSymbol;
var namedSource = source.TupleUnderlyingTypeOrSelf() as NamedTypeSymbol;
Copy link
Member

Choose a reason for hiding this comment

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

NIT: I'd put this in the caller to be sure unwrap is not called when we do not expect. However, since there is only one caller, unwrapping here seems ok as well.

Copy link
Member

@VSadov VSadov left a comment

Choose a reason for hiding this comment

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

:shipit:

Copy link
Member

@VSadov VSadov left a comment

Choose a reason for hiding this comment

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

LGTM

' First try to the things directly. Only if this fails will we bother searching for things like List->IEnumerable.
Dim Inferred As Boolean = InferTypeArgumentsFromArgumentDirectly(
Dim addedDirectHints As Boolean = False
Dim directInferenceResult As Boolean = InferTypeArgumentsFromArgumentDirectly(
Copy link
Member

Choose a reason for hiding this comment

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

Offline, @AlekseyTs explained to me that this is being used to fix a separate, unreported bug in the VB compiler whereby an invocation fails in certain situations when one argument fails to contribute to the inference of one type parameter, even though that type parameter can be inferred from another argument. See the change in TypeArgumentInference.vb for a test more focused on that bug. However, it seems that this fix should be done on a type parameter by type parameter basis, as the language requires each type parameter to be inferred from some argument (not just one of them). By tracking this as a single bool, it would appear to permit an invocation to succeed (because some type parameter was inferred from an argument) even though some other type parameter was not inferred from an argument. I think a correct fix would require a Dictionary<TypeParameterSymbol, Boolean> rather than a single Boolean to be correct.

I would suggest either fixing this correcly, or leaving this bug unfixed in VB for now (i.e. reverting the VB changes).

@AlekseyTs
Copy link
Contributor Author

@gafter I believe your feedback has been addressed.

@@ -1633,6 +1629,10 @@ HandleAsAGeneralExpression:
inferenceRestrictions As RequiredConversion
) As Boolean

If Not RefersToGenericParameterToInferArgumentFor(parameterType) Then
Copy link
Member

Choose a reason for hiding this comment

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

RefersToGenericParameterToInferArgumentFor [](start = 23, length = 42)

I think the name of RefersToGenericParameterToInferArgumentFor should be RefersToGenericParameterToInferTypeArgument if I understand its purpose.

Copy link
Member

@gafter gafter left a comment

Choose a reason for hiding this comment

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

:shipit:

@AlekseyTs AlekseyTs merged commit 133364a into dotnet:master Sep 26, 2017
333fred added a commit to 333fred/roslyn that referenced this pull request Sep 28, 2017
* dotnet/master: (35 commits)
  removed unused options (dotnet#22389)
  Make readonlyness of ref-ternary the AND of operands (dotnet#22384)
  Refine parsing look-ahead for type arguments (dotnet#22102)
  IDE Features fix for code generation for ref-readonly (dotnet#22285)
  Added tests for `out` and `ref` completion in local function
  Record "allow digit separator after 0b or 0x" (dotnet#22371)
  Responded to feedback
  Don't show snippets in VB comments
  Fix bug when trailing and leading underscores are not the same (dotnet#22141)
  Add breaking change doc for TypedReference delegate conversion. (dotnet#22084)
  Add no-PDB-path test for VB
  Ref ternary shoudl be shielded form optimization in the containing expression that may expose it to mutations
  Improve method type argument inference around tuples and address backwards compatibility break. (dotnet#22295)
  Added couple more tests
  Add unit tests for IStopStatement and IEndStatement and make the APIs public again (dotnet#22225)
  Revert changes to compilers.sln
  Support for object initializers.
  supports all expressions in escape analysis that can possibly produce ref-like values
  Update tests after merge.
  Add an option to disable name suggestions
  ...
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.

6 participants