Skip to content

Move features over to new "simplifier + var" system.#26237

Merged
heejaechang merged 109 commits intodotnet:masterfrom
CyrusNajmabadi:moveVarDown2
Apr 20, 2018
Merged

Move features over to new "simplifier + var" system.#26237
heejaechang merged 109 commits intodotnet:masterfrom
CyrusNajmabadi:moveVarDown2

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

No description provided.

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner April 18, 2018 19:20
@CyrusNajmabadi CyrusNajmabadi changed the title WIP: validate that features can just depend on the simplifier to do the right thing. Falidate that features can just depend on the simplifier to do the right thing wrt var. Apr 18, 2018
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Tagging @DustinCampbell as i had to make a couple of interesting behavioral choices. I've tagged you where i made them so you can weigh in if the change is ok.

ImmutableArray.Create<AbstractReducer>(
new CSharpCastReducer(),
new CSharpNameReducer(),
new CSharpCastReducer(),
Copy link
Copy Markdown
Contributor Author

@CyrusNajmabadi CyrusNajmabadi Apr 18, 2018

Choose a reason for hiding this comment

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

@DustinCampbell This was the interesting starting point. One of our features (convert foreach to for) generates code like so:

IList<int> list = (IList<int>)collection;

Previous behavior was that it wanted this to change into:

var list = (IList<int>)collection;

However, after my change it converted to:

IList<int> list = collection;

This was due to the 'cast' reducer running before the name reducer. IMO, if someone expresses a 'var' preference, i think that should take preference, so i changed to have name-reduction happen before cast-reduction. However, this had observable downstream impacts in a few tests that i've called out.

Take a look at the changed tests and let me know waht you think. Should name reduction come before cast reduction, or vice versa?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is fine.

There was some reason why we reduced casts twice here, but I don't recall what it was and it doesn't appear to have been problematic for any existing tests. Regardless, it always felt like a hack.

I kind of wish the generic method argument simplification was implemented as a separate reducer rather than part of the name reducer so we could just move it below the cast reducer, but I think it's fine for now.

{
byte z = 0;
Goo<byte, byte>({|Rename:NewMethod|}(), y => { return 0; }, z, z);
Goo({|Rename:NewMethod|}(), y => { return (byte)0; }, z, z);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@DustinCampbell see https://github.com/dotnet/roslyn/pull/26237/files#r182592374

Now, we attempt to simplify the name first rather than the cast first, so we get this behavior. IMO, i think the new code is preferable to the old. Using inference for generic methods is very preferred (especially as you might end up having to name a lot of type parameters), so i think we should attempt to preserve inference first, even if it means we have to keep some casts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, this is definitely better.

static void M()
{
IComparable<long> c = Goo<long>(1, 1);
IComparable<long> c = Goo(1, (long)1);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@DustinCampbell see https://github.com/dotnet/roslyn/pull/26237/files#r182592374

This is the same as the above test. Humorously, this test is called "InsertCastToKeepGenericMethodInference". So it sounds like we did actually intend for their to be a cast, rather than keeping the type parameters.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, simplification of generic method arguments was added to the system later. I agree that the new version is preferred (at least to my eye). Maybe someday, we'll add simplification to type characters (as an option of course!).

IComparable<long> c = Goo(1, 1L);

😄

byte z = 0;
Func<byte, byte> {|Rename:p|} = x => 0;
Goo<byte, byte>(p, y => 0, z, z);
Goo(p, y => (byte)0, z, z);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@DustinCampbell see https://github.com/dotnet/roslyn/pull/26237/files#r182592374

This is the same as the above test. Humorously, this test is called "InsertNeededCast2". So it sounds like we did actually intend for their to be a cast, rather than keeping the type parameters.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yup. It was originally a Nikov case. I like the change here.

public Enumerator GetEnumerator() { return default; }

public struct Enumerator { public object Current { get; } }
public struct Enumerator { public object Current { get; } public bool MoveNext() => true; }
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

needed to make this change, otherwise the compiler felt that the type didn't properly match the 'foreach' pattern, and didn't want to consider hte types the same for reduction.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

? foreachInfo.ExplicitCastInterface
: model.GetTypeInfo(foreachCollectionExpression).Type ?? model.Compilation.GetSpecialType(SpecialType.System_Object);

var collectionStatementType = typeSymbol.GenerateTypeSyntax();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

these are the places where i updated our features to now just use 'GenerateTypeSyntax()' confident that the simplifier would now use 'var' if htat's what the user wanted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awesome. It's definitely simpler.

@CyrusNajmabadi CyrusNajmabadi changed the title Falidate that features can just depend on the simplifier to do the right thing wrt var. Validate that features can just depend on the simplifier to do the right thing wrt var. Apr 19, 2018
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Tagging @dotnet/roslyn-ide @jcouv @jmarolf as well.

@CyrusNajmabadi CyrusNajmabadi changed the title Validate that features can just depend on the simplifier to do the right thing wrt var. Move features over to new "simplifier + var" system. Apr 19, 2018
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Tagging @dotnet/roslyn-ide @jcouv @heejaechang

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Tagging @ivanbasov this will likely impact your foreach/linq work.

@heejaechang
Copy link
Copy Markdown
Contributor

nice! we should have other code styles as well such as having "this." or not and etc.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

nice! we should have other code styles as well such as having "this." or not and etc.

Indeed, IMO, all the codestyle stuff should be enforced on nodes marked with the Simplifier Annotatoin when passed through the simplifier.

@DustinCampbell
Copy link
Copy Markdown
Member

Indeed, IMO, all the codestyle stuff should be enforced on nodes marked with the Simplifier Annotatoin when passed through the simplifier.

This was always the original intent.

Copy link
Copy Markdown
Member

@DustinCampbell DustinCampbell left a comment

Choose a reason for hiding this comment

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

I'm definitely in favor of this change. The changes to the unit tests represent simpler, yet still correct, code which was always the intent of the feature. Thanks @CyrusNajmabadi!

static void M()
{
IComparable<long> c = Goo<long>(1, 1);
IComparable<long> c = Goo(1, (long)1);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, simplification of generic method arguments was added to the system later. I agree that the new version is preferred (at least to my eye). Maybe someday, we'll add simplification to type characters (as an option of course!).

IComparable<long> c = Goo(1, 1L);

😄

{
byte z = 0;
Goo<byte, byte>({|Rename:NewMethod|}(), y => { return 0; }, z, z);
Goo({|Rename:NewMethod|}(), y => { return (byte)0; }, z, z);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, this is definitely better.

byte z = 0;
Func<byte, byte> {|Rename:p|} = x => 0;
Goo<byte, byte>(p, y => 0, z, z);
Goo(p, y => (byte)0, z, z);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yup. It was originally a Nikov case. I like the change here.

public Enumerator GetEnumerator() { return default; }

public struct Enumerator { public object Current { get; } }
public struct Enumerator { public object Current { get; } public bool MoveNext() => true; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

? foreachInfo.ExplicitCastInterface
: model.GetTypeInfo(foreachCollectionExpression).Type ?? model.Compilation.GetSpecialType(SpecialType.System_Object);

var collectionStatementType = typeSymbol.GenerateTypeSyntax();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awesome. It's definitely simpler.

ImmutableArray.Create<AbstractReducer>(
new CSharpCastReducer(),
new CSharpNameReducer(),
new CSharpCastReducer(),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is fine.

There was some reason why we reduced casts twice here, but I don't recall what it was and it doesn't appear to have been problematic for any existing tests. Regardless, it always felt like a hack.

I kind of wish the generic method argument simplification was implemented as a separate reducer rather than part of the name reducer so we could just move it below the cast reducer, but I think it's fine for now.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Thanks @DustinCampbell I'll see if i can start pushing more and more stuff to the simplifier.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@heejaechang @jmarolf @DustinCampbell can one of you merge in?

@heejaechang heejaechang merged commit 04d57fd into dotnet:master Apr 20, 2018
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Thanks!

@CyrusNajmabadi CyrusNajmabadi deleted the moveVarDown2 branch September 17, 2022 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants