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

Enable implicit “this” in default interface implementations. #18393

Merged

Conversation

AlekseyTs
Copy link
Contributor

@dotnet/roslyn-compiler Please review.

I2.set_P3
I2.add_E3
I2.remove_E3
I2.get_P2
Copy link
Member

Choose a reason for hiding this comment

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

Consider some additional formatting to improve readability. Maybe add "## " on the "headers".


CompileAndVerify(compilation1, verify: false);

/* Expected output
Copy link
Member

Choose a reason for hiding this comment

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

PROTOTYPE?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Running success scenarios is tracked in #17952.

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

@AlekseyTs
Copy link
Contributor Author

@dotnet/roslyn-compiler Please review, need a second sign-off.

@@ -1319,7 +1319,7 @@ private BoundExpression SynthesizeMethodGroupReceiver(CSharpSyntaxNode syntax, A
var declaringType = members[0].ContainingType;

HashSet<DiagnosticInfo> unused = null;
if (currentType.IsEqualToOrDerivedFrom(declaringType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref unused))
if (currentType.IsInterface || currentType.IsEqualToOrDerivedFrom(declaringType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref unused))
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is correct for an interface nested within a class that does not implement the interface. If we find a method invocation of an instance method of the enclosing class, this would appear to return an incompatible "this". The design of this method would appear to require that null be returned rather than an incompatible receiver. Here is the scenario:

class A
{
    public void M() {}
    interface I
    {
        void N() { M(); } // what `this` here?
    }
}

I suspect the correct fix is to use something other than (or modify) IsEqualToOrDerivedFrom, which considers only non-interface inheritance.

The alternative is to remove the test for reference-relatedness from this method entirely and rely on a mechanism for that to be checked elsewhere, if you believe that such a larger refactoring has other benefits.

Please add tests for nested types, and specifically implicit receivers for invocations of names found on or inherited into enclosing types.

@@ -1538,7 +1538,7 @@ private BoundExpression SynthesizeReceiver(CSharpSyntaxNode node, Symbol member,
var currentType = this.ContainingType;
HashSet<DiagnosticInfo> useSiteDiagnostics = null;

if (currentType.IsEqualToOrDerivedFrom(member.ContainingType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref useSiteDiagnostics))
if (currentType.IsInterface || currentType.IsEqualToOrDerivedFrom(member.ContainingType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: 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.

Same issue here.

@AlekseyTs
Copy link
Contributor Author

@gafter I believe I've addressed your feedback, please take a look.

@AlekseyTs
Copy link
Contributor Author

@dotnet/roslyn-compiler Please review, need a second sign-off.

@@ -1319,7 +1319,8 @@ private BoundExpression SynthesizeMethodGroupReceiver(CSharpSyntaxNode syntax, A
var declaringType = members[0].ContainingType;

HashSet<DiagnosticInfo> unused = null;
if (currentType.IsEqualToOrDerivedFrom(declaringType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref unused))
if (currentType.IsEqualToOrDerivedFrom(declaringType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref unused) ||
(currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType))))
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)

This is not correct for an invocation of an interface method from a class nested within the interface. Although you have not implemented classes declared within interfaces yet, I do not think it makes sense to add code here that will just have to be changed again.

Copy link
Member

Choose a reason for hiding this comment

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

Are there tests that distinguish this if statement's condition from (currentType == declaringType) thereby illustrating the importance of the test for related types here?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see declaringType has nothing to do with the T quoted in the spec, above. That means that the "If T is the instance type of the immediately enclosing class or struct type..." part of the quoted spec isn't implemented. Anywhere. This relatedness test appears intended to imitate that test, but it does not do so correctly in cases involving hiding. As a consequence, this implementation would appear to get the hiding cases wrong.

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.

LGTM. I filed a bug for the existing issue about hiding in nested scenarios.

@AlekseyTs AlekseyTs merged commit 0814ad1 into dotnet:features/DefaultInterfaceImplementation Apr 6, 2017
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