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

[AST] #SR-13906 (Improvement) Error Messages #35238

Closed

Conversation

aniket-ray
Copy link

@aniket-ray aniket-ray commented Dec 29, 2020

Resolves SR-13906
https://bugs.swift.org/browse/SR-13906

Updated Error message for types trying to conform to AnyObject or its Composition for better user understandability.

For instance:

protocol P {}
typealias Q = P & AnyObject
struct S: Q {}
enum T: P & AnyObject {}
struct U: P, AnyObject {}

Before :

error: inheritance from non-protocol type 'Q' (aka 'P & AnyObject')
struct S: Q {}
       ^
error: inheritance from non-protocol type 'P & AnyObject'
enum T: P & AnyObject {}
     ^
error: inheritance from non-protocol, non-class type 'AnyObject'
class U: P, AnyObject {}
       ^

After :

error: Non-protocol 'S' cannot conform to composition 'Q' (aka 'P & AnyObject'). Composition 'Q' (aka 'P & AnyObject') involves 'AnyObject'
struct S: Q {}
       ^
error: Non-protocol 'T' cannot conform to composition 'P & AnyObject'. Composition 'P & AnyObject' involves 'AnyObject'
enum T: P & AnyObject {}
     ^
error: inheritance from non-protocol type 'AnyObject'
struct U: P, AnyObject {}
       ^

@aniket-ray
Copy link
Author

Code Review and Suggestions: @CodaFi @augusto2112

Copy link
Contributor

@augusto2112 augusto2112 left a comment

Choose a reason for hiding this comment

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

Congratulations on your first PR! 🎉

@@ -235,10 +235,16 @@ static void checkInheritanceClause(
// AnyObject is not allowed except on protocols.
if (layout.hasExplicitAnyObject &&
!isa<ProtocolDecl>(decl)) {
decl->diagnose(canHaveSuperclass
if(!layout.isAnyObject()){
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should add a comment here explaining why this must be a composition (since we know that layout.hasExplicitAnyObject is true).

Copy link
Author

Choose a reason for hiding this comment

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

Added Comments

if(!layout.isAnyObject()){
decl->diagnose(diag::composition_of_protocol_and_AnyObject, typeDecl->getName() ,inheritedTy);
}
else{
Copy link
Contributor

@augusto2112 augusto2112 Dec 29, 2020

Choose a reason for hiding this comment

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

Did you run clang-format? I think the usual llvm style is:

if (condition) {
} else {
}

Copy link
Author

Choose a reason for hiding this comment

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

Ran clang-format and conformed to the LLVM Style.

@aniket-ray aniket-ray force-pushed the Improvement_SR-13906_ErrorMessage branch from ef3916a to 85b66bf Compare December 29, 2020 21:33
Copy link
Contributor

@CodaFi CodaFi left a comment

Choose a reason for hiding this comment

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

This is a good start. I think we can make a few more tweaks and it'll be good to go.

@@ -2662,6 +2662,8 @@ ERROR(inheritance_from_cf_class,none,
ERROR(inheritance_from_objc_runtime_visible_class,none,
"cannot inherit from class %0 because it is only visible via the "
"Objective-C runtime", (Identifier))
ERROR(composition_of_protocol_and_AnyObject,none,
"Non-protocol %0 cannot conform to composition %1. Composition %1 involves 'AnyObject'", (Identifier, Type))
Copy link
Contributor

Choose a reason for hiding this comment

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

While I appreciate your good punctuation and grammar here, diagnostics have a distinct formatting style. They

  • don't begin with capital letters
  • rarely involve multiple sentences - when they run on, we use semicolons or break the second part into a note.

Copy link
Contributor

Choose a reason for hiding this comment

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

We have this document to lay out the common conventions.

Copy link
Author

Choose a reason for hiding this comment

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

We can do something like non-protocol type %0 cannot conform to composition type %1 and omit the Composition %1 involves 'AnyObject' part.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I still think we ought to highlight the AnyObject part of the composition in the message in some way. What might help is to think about this in isolation and come up with a "headline". That's usually a good way to write a diagnostic.

// Check if the inherited type is exclusively AnyObject
// If not, we can be sure of the composition of Protocol(s) with
// AnyObject
if (!layout.isAnyObject()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's more important to break up the diagnostic in the else by making it more specific and using less compiler-jargon-ified language.

Copy link
Author

Choose a reason for hiding this comment

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

You mean breaking down the ternary operator to if-else for canHaveSuperClass?

Copy link
Contributor

Choose a reason for hiding this comment

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

The intent of the original bug was to fix this particular ternary by providing a more specific message. Its branches are the cause of the confusion here.

@@ -2662,6 +2662,8 @@ ERROR(inheritance_from_cf_class,none,
ERROR(inheritance_from_objc_runtime_visible_class,none,
"cannot inherit from class %0 because it is only visible via the "
"Objective-C runtime", (Identifier))
ERROR(composition_of_protocol_and_AnyObject,none,
Copy link
Contributor

Choose a reason for hiding this comment

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

Also, normally diagnostic ids are all lower case so this would be composition_of_protocol_and_anyobject :)

Copy link
Author

Choose a reason for hiding this comment

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

Noted!

Aniket Ray added 2 commits January 18, 2021 09:27
Updated Error message for types conforming to
AnyObject or its Composition
@aniket-ray aniket-ray force-pushed the Improvement_SR-13906_ErrorMessage branch from 85b66bf to aad3bc6 Compare January 18, 2021 15:10
@aniket-ray
Copy link
Author

Testing Time: 5781.66s
  Unsupported      :  224
  Passed           : 6249
  Expectedly Failed:   24

5 warning(s) in tests

@@ -55,7 +55,7 @@ func testGenericInherit() {
}


struct SS<T> : T { } // expected-error{{inheritance from non-protocol type 'T'}}
struct SS<T> : T { } // expected-error{{generic struct type cannot inherit from non-protocol type 'T'giy }}
Copy link
Contributor

Choose a reason for hiding this comment

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

giy seems like a typo here :)


// Protocol inheriting a class
protocol Q : A { }

// Extension inheriting a class
extension C : A { } // expected-error{{inheritance from non-protocol type 'A'}}
extension C : A { } // expected-error{{extension type cannot inherit from non-protocol type 'A'}}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that there is no such term as extension type, to me this should be the same diagnostic as class C: A {} class type cannot inherit ...

@@ -2662,6 +2662,11 @@ ERROR(inheritance_from_cf_class,none,
ERROR(inheritance_from_objc_runtime_visible_class,none,
"cannot inherit from class %0 because it is only visible via the "
"Objective-C runtime", (Identifier))
ERROR(composition_of_protocol_and_anyobject,none,
Copy link
Contributor

Choose a reason for hiding this comment

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

I see there is this tailored diagnostic for composition but not a regression test case for exercise it. We should add the respective test :)

decl->diagnose(diag::composition_of_protocol_and_anyobject,
typeDecl->getName(), inheritedTy);
} else {
decl->diagnose(canHaveSuperclass
Copy link
Contributor

@augusto2112 augusto2112 Jan 19, 2021

Choose a reason for hiding this comment

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

I think the comment left by Codafi, of addressing the else block still needs to be done.

@xwu
Copy link
Collaborator

xwu commented Apr 27, 2023

Looks like #41537 has addressed SR-13906, superseding this PR.

@xwu xwu closed this Apr 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants