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

[CS2] Throw an error for ambiguous get or set keywords or function calls #4484

Merged
merged 10 commits into from
Apr 9, 2017
6 changes: 4 additions & 2 deletions lib/coffeescript/lexer.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/lexer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ exports.Lexer = class Lexer
isForFrom(prev)
tag = 'FORFROM'
@seenFor = no
else if tag is 'PROPERTY' and prev and prev.spaced and prev[0] in CALLABLE and /^[g|s]et$/.test(prev[1])
Copy link
Collaborator

Choose a reason for hiding this comment

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

The [g|s] should simply be [gs].

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Damn. You win.

Copy link
Collaborator

Choose a reason for hiding this comment

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

For the record, that's not just shorter but also more correct. [g|s]et would also match |et.

@error "'#{prev[1]}' cannot be used as a keyword, or as a function call without parentheses", prev[2]

if tag is 'IDENTIFIER' and id in RESERVED
@error "reserved word '#{id}'", length: id.length
Expand Down
2 changes: 1 addition & 1 deletion src/nodes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ exports.Call = class Call extends Base
constructor: (@variable, @args = [], @soak) ->
super()

@isNew = false
@isNew = no
if @variable instanceof Value and @variable.isNotCallable()
@variable.error "literal is not a function"

Expand Down
116 changes: 116 additions & 0 deletions test/error_messages.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -1340,3 +1340,119 @@ test "new with 'super'", ->
class extends A then foo: -> new super()
^^^^^
'''

test "getter keyword in object", ->
assertErrorFormat '''
obj =
get foo: ->
''', '''
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
get foo: ->
^^^
'''

test "setter keyword in object", ->
assertErrorFormat '''
obj =
set foo: ->
''', '''
[stdin]:2:3: error: 'set' cannot be used as a keyword, or as a function call without parentheses
set foo: ->
^^^
'''

test "getter keyword in inline implicit object", ->
assertErrorFormat 'obj = get foo: ->', '''
[stdin]:1:7: error: 'get' cannot be used as a keyword, or as a function call without parentheses
obj = get foo: ->
^^^
'''

test "setter keyword in inline implicit object", ->
assertErrorFormat 'obj = set foo: ->', '''
[stdin]:1:7: error: 'set' cannot be used as a keyword, or as a function call without parentheses
obj = set foo: ->
^^^
'''

test "getter keyword in inline explicit object", ->
assertErrorFormat 'obj = {get foo: ->}', '''
[stdin]:1:8: error: 'get' cannot be used as a keyword, or as a function call without parentheses
obj = {get foo: ->}
^^^
'''

test "setter keyword in inline explicit object", ->
assertErrorFormat 'obj = {set foo: ->}', '''
[stdin]:1:8: error: 'set' cannot be used as a keyword, or as a function call without parentheses
obj = {set foo: ->}
^^^
'''

test "getter keyword in function", ->
assertErrorFormat '''
f = ->
get foo: ->
''', '''
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
get foo: ->
^^^
'''

test "setter keyword in function", ->
assertErrorFormat '''
f = ->
set foo: ->
''', '''
[stdin]:2:3: error: 'set' cannot be used as a keyword, or as a function call without parentheses
set foo: ->
^^^
'''

test "getter keyword in inline function", ->
assertErrorFormat 'f = -> get foo: ->', '''
[stdin]:1:8: error: 'get' cannot be used as a keyword, or as a function call without parentheses
f = -> get foo: ->
^^^
'''

test "setter keyword in inline function", ->
assertErrorFormat 'f = -> set foo: ->', '''
[stdin]:1:8: error: 'set' cannot be used as a keyword, or as a function call without parentheses
f = -> set foo: ->
^^^
'''

test "getter keyword in class", ->
assertErrorFormat '''
class A
get foo: ->
''', '''
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
get foo: ->
^^^
'''

test "setter keyword in class", ->
assertErrorFormat '''
class A
set foo: ->
''', '''
[stdin]:2:3: error: 'set' cannot be used as a keyword, or as a function call without parentheses
set foo: ->
^^^
'''

test "getter keyword in inline class", ->
assertErrorFormat 'class A then get foo: ->', '''
[stdin]:1:14: error: 'get' cannot be used as a keyword, or as a function call without parentheses
class A then get foo: ->
^^^
'''

test "setter keyword in inline class", ->
assertErrorFormat 'class A then set foo: ->', '''
[stdin]:1:14: error: 'set' cannot be used as a keyword, or as a function call without parentheses
class A then set foo: ->
^^^
'''
40 changes: 39 additions & 1 deletion test/function_invocation.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ test "Non-callable literals shouldn't compile", ->
cantCompile '[1..10][2..9] 2'
cantCompile '[1..10][2..9](2)'

test 'implicit invocation with implicit object literal', ->
test "implicit invocation with implicit object literal", ->
f = (obj) -> eq 1, obj.a

f
Expand Down Expand Up @@ -706,3 +706,41 @@ test 'implicit invocation with implicit object literal', ->
else
"#{a}": 1
eq 2, obj.a

test "get and set can be used as function names when not ambiguous with `get`/`set` keywords", ->
get = (val) -> val
set = (val) -> val
eq 2, get(2)
eq 3, set(3)

get = ({val}) -> val
set = ({val}) -> val
eq 4, get({val: 4})
eq 5, set({val: 5})

test "get and set can be used as variable and property names", ->
get = 2
set = 3
eq 2, get
eq 3, set

{get} = {get: 4}
{set} = {set: 5}
eq 4, get
eq 5, set

test "get and set can be used as class method names", ->
class A
get: -> 2
set: -> 3

a = new A()
eq 2, a.get()
eq 3, a.set()

class B
@get = -> 4
@set = -> 5

eq 4, B.get()
eq 5, B.set()