Skip to content

[SR-8340]Improve fix-it for var and subscript in Protocol #19660

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

Merged
merged 10 commits into from
Oct 4, 2018

Conversation

mzp
Copy link
Contributor

@mzp mzp commented Oct 2, 2018

Improve fix-it for following code to resolves SR-8340.

protocol P {
  subscript() -> Bool 
  // before: insert "{ get set }"
  // after: insert "{ get <#set#> }"

  var v : Bool
  // before: No fixit (error message only)
  // after: insert "{ get <#set#> } "

  let n : Bool
  // before: No fixit (error message only)
  // after: replace with "var" and insert "{ get } "
}

@mzp mzp changed the title Improve fix-it for var and subscript in Protocol [SR-8340]Improve fix-it for var and subscript in Protocol Oct 2, 2018
@jrose-apple jrose-apple requested review from rintaro and xedin October 2, 2018 18:22
xedin
xedin previously requested changes Oct 3, 2018
Copy link
Contributor

@xedin xedin 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 definitely a nice improvement, thank you! One thing - it looks like you should use getSourceRange() while replacing let with var, otherwise it would just insert var and keep let or rather et I think...

One way to validate everything would be to do @swift-ci build toolchain and verify in Xcode.

@rintaro
Copy link
Member

rintaro commented Oct 3, 2018

I believe fixItReplace(...->getLoc(), "var") is OK because fixItReplace() receives only SourceRange and SourceLoc is converted to SourceRange automatically.
Of course we need test cases, though.

@@ -502,6 +502,7 @@ protocol LetThereBeCrash {
let x: Int
// expected-error@-1 {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}}
// expected-note@-2 {{declared here}}
// {{13-13= { get \}}}
Copy link
Member

Choose a reason for hiding this comment

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

This {{ ... }} belongs to the line 503 (2 lines above)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed at f0f33eb

@@ -454,7 +454,7 @@ protocol ShouldntCrash {
let fullName: String { get } // expected-error {{'let' declarations cannot be computed properties}} {{3-6=var}}

// <rdar://problem/17200672> Let in protocol causes unclear errors and crashes
let fullName2: String // expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}}
let fullName2: String // expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} {{24-24= { get \}}}
Copy link
Member

Choose a reason for hiding this comment

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

I believe this diagnostics emits {{3-6=var}} as well.

Small tip: Try adding {{none}} without adding {{3-6=var}}. That should fail with fixit for test-cases. e.g.

test.swift:2:57: error: expected no fix-its; actual fix-it seen: {{11-11=,}}
  "foo": 1 // expected-error {{expected ',' separator}} {{none}}
                                                        ^~~~~~~
                                                        {{11-11=,}}

You can paste it. (after you confirmed it's expected, of course)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wow, it's useful tip.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed at 7d35c95

@@ -850,10 +850,10 @@ struct WillSetDidSetDisambiguate3 {
}

protocol ProtocolGetSet1 {
var a: Int // expected-error {{property in protocol must have explicit { get } or { get set } specifier}}
var a: Int // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} //{{13-13= { get <#set#> \}}}
Copy link
Member

Choose a reason for hiding this comment

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

Remove // before {{13-13....

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed at f1d830a

@@ -12,6 +12,7 @@ protocol SomeProtocol {
lazy var x : Int // expected-error {{'lazy' isn't allowed on a protocol requirement}} {{3-8=}}
// expected-error@-1 {{property in protocol must have explicit { get } or { get set } specifier}}
// expected-error@-2 {{lazy properties must have an initializer}}
// {{18-18= { get set \}}}
Copy link
Member

Choose a reason for hiding this comment

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

This fix-it belongs to line 13.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if (braces.isValid())
diag
.fixItReplace(var->getParentPatternBinding()->getLoc(), "var")
.fixItReplace(braces, " { get }");
Copy link
Member

@rintaro rintaro Oct 3, 2018

Choose a reason for hiding this comment

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

It looks like we don't have test cases for this path. Is this possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added test case at da9a19b

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 the test case added in da9a19b is actually testing this code path.
If so, the fix-it should be {{14-32= { get \}}} instead of {{14-32={ get <#set#> \}}}.
Currently, even if it's spelled with let, the parser creates non-let PatternBindingDecl if the decl has accessor block.

I think it's OK to remove if (braces.isValid()) block here.

@@ -6226,7 +6226,7 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags,
if (!Status.isError()) {
if (Flags.contains(PD_InProtocol)) {
diagnose(Tok, diag::expected_lbrace_subscript_protocol)
.fixItInsertAfter(ElementTy.get()->getEndLoc(), " { get set }");
.fixItInsertAfter(ElementTy.get()->getEndLoc(), " { get <#set#> }");
Copy link
Member

Choose a reason for hiding this comment

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

Generally, editor place holder (<#...#>) doesn't mean it's optional. Instead, we expect developers to replace it with actual code. But I admit it's handy in Xcode. (tab navigation, return key inserts set, single del key removes the placeholder).

@jrose-apple Any concern about this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I found it a little funny too, but I think it's reasonable. @nkcsgexi might also be a good person to ask.

Copy link
Contributor

Choose a reason for hiding this comment

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

it seems reasonable to me as well. One benefit of placeholder is being easy to remove or being made solid, which i believe is @mzp 's motivation here to include set as a placeholder.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, the <#set#> was my idea, and that was my motivation.
I made SR-8340.

auto diag = TC.diagnose(var->getLoc(), diag::protocol_property_must_be_computed);

if (braces.isValid())
diag.fixItReplace(braces, " { get <#set#> }");
Copy link
Member

Choose a reason for hiding this comment

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

" { adds extra space.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

striped at 7ae9eb7

@xedin
Copy link
Contributor

xedin commented Oct 3, 2018

@rintaro SourceLoc forms a single chacter SourceRange, that’s why I don’t think that it’s desirable here

@jrose-apple
Copy link
Contributor

jrose-apple commented Oct 3, 2018

SourceLoc does not form a single-character SourceRange; it forms a single-token SourceRange. You're mixing up SourceRange and CharSourceRange.

@xedin
Copy link
Contributor

xedin commented Oct 3, 2018

Ah, okay so it's just going to wrap the whole let token, that's reasonable then!

@xedin xedin dismissed their stale review October 3, 2018 17:49

I mixed up couple of things

@mzp
Copy link
Contributor Author

mzp commented Oct 4, 2018

I pushed changes to fix commented code.

@xedin
Copy link
Contributor

xedin commented Oct 4, 2018

@swift-ci please smoke test

if (braces.isValid())
diag
.fixItReplace(var->getParentPatternBinding()->getLoc(), "var")
.fixItReplace(braces, " { get }");
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 the test case added in da9a19b is actually testing this code path.
If so, the fix-it should be {{14-32= { get \}}} instead of {{14-32={ get <#set#> \}}}.
Currently, even if it's spelled with let, the parser creates non-let PatternBindingDecl if the decl has accessor block.

I think it's OK to remove if (braces.isValid()) block here.

if (braces.isValid())
diag.fixItReplace(braces, "{ get <#set#> }");
else
diag.fixItInsertAfter(var->getTypeLoc().getLoc(), " { get <#set#> }");
Copy link
Member

Choose a reason for hiding this comment

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

Do we have test cases without type annotation? like:

protocol P {
   let foo
   var bar
}

If not, could you add them?
In these cases, ->getTypeLoc().getLoc() is invalid, so this fix-it should be ignored.
Just in case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's OK to remove if (braces.isValid()) block here.

Your pointed-out is correct. I remove it at 1ddfa58.

Do we have test cases without type annotation?

I could not find such testcase. So, I added it in fd5f3ff.

@rintaro
Copy link
Member

rintaro commented Oct 4, 2018

@swift-ci Please smoke test

Copy link
Member

@rintaro rintaro left a comment

Choose a reason for hiding this comment

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

Thanks!

@rintaro rintaro merged commit f2bdce8 into swiftlang:master Oct 4, 2018
modelorganism pushed a commit to modelorganism/swift that referenced this pull request Oct 11, 2018
…19660)

* [Parser] Improve fix-it for subscription in protocol
* [Sema] Add fix-it for property in protocol

https://bugs.swift.org/browse/SR-8340
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.

6 participants