Skip to content

Commit 296cd5e

Browse files
authored
AST: parse a.b as (. a b) (#325)
I was working a bit on macro expansion - particularly `quote` (quasiquote) expansion with `$` interpolations - and I've found that it's weird and inconvenient that we parse `a.b` into `(. a (quote b))`. Specifically, the part that's weird here is that we emit `(quote b)` for the field name even though this is "not quote syntax": this should not yield a syntax literal during lowering, and is thus a semantic mismatch with actual quote syntax of the form `:(a + b)` or `quote a+b end`. * Why is this a problem? It means we need special rules to distinguish actual syntax literals from field names. * But can we really change this? Surely this AST form had a purpose? Yes! A long time ago Julia supported `a.(b)` syntax to mean `getfield(a, b)`, which would naturally have been parsed as `(. a b)`. However this was deprecated as part of adding broadcast syntax in JuliaLang/julia#15032 Here we simplify by parsing `a.b` as `(. a b)` instead, with the second argument implied to be a field name.
1 parent 5aad812 commit 296cd5e

File tree

5 files changed

+81
-74
lines changed

5 files changed

+81
-74
lines changed

docs/src/reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class of tokenization errors and lets the parser deal with them.
6464

6565
### Improvements for AST inconsistencies
6666

67+
* Field access syntax like `a.b` is parsed as `(. a b)` rather than `(. a (quote b))` to avoid the inconsistency between this and actual quoted syntax literals like `:(b)` and `quote b end` ([#342](https://github.com/JuliaLang/JuliaSyntax.jl/issues/324))
6768
* Dotted call syntax like `f.(a,b)` and `a .+ b` has been made consistent with the `K"dotcall"` head (#90)
6869
* Standalone dotted operators are always parsed as `(. op)`. For example `.*(x,y)` is parsed as `(call (. *) x y)` (#240)
6970
* The `K"="` kind is used for keyword syntax rather than `kw`, to avoid various inconsistencies and ambiguities (#103)

src/expr.jl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,17 @@ function _internal_node_to_Expr(source, srcrange, head, childranges, childheads,
259259
args[1] = Symbol(".", args[1])
260260
end
261261
end
262-
elseif k == K"." && length(args) == 1 && is_operator(childheads[1])
263-
# Hack: Here we preserve the head of the operator to determine whether
264-
# we need to coalesce it with the dot into a single symbol later on.
265-
args[1] = (childheads[1], args[1])
262+
elseif k == K"."
263+
if length(args) == 2
264+
a2 = args[2]
265+
if !@isexpr(a2, :quote) && !(a2 isa QuoteNode)
266+
args[2] = QuoteNode(a2)
267+
end
268+
elseif length(args) == 1 && is_operator(childheads[1])
269+
# Hack: Here we preserve the head of the operator to determine whether
270+
# we need to coalesce it with the dot into a single symbol later on.
271+
args[1] = (childheads[1], args[1])
272+
end
266273
elseif k == K"ref" || k == K"curly"
267274
# Move parameters blocks to args[2]
268275
_reorder_parameters!(args, 2)

src/parser.jl

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ end
14371437
# * Adjoint suffix like a'
14381438
# * String macros like a"str" b"""str""" c`str` d```str```
14391439
#
1440-
# f(a).g(b) ==> (call (. (call f a) (quote g)) b)
1440+
# f(a).g(b) ==> (call (. (call f a) g) b)
14411441
#
14421442
# flisp: parse-call-chain, parse-call-with-initial-ex
14431443
function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
@@ -1448,7 +1448,7 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
14481448
end
14491449
# source range of the @-prefixed part of a macro
14501450
macro_atname_range = nothing
1451-
# $A.@x ==> (macrocall (. ($ A) (quote @x)))
1451+
# $A.@x ==> (macrocall (. ($ A) @x))
14521452
maybe_strmac = true
14531453
# We record the last component of chains of dot-separated identifiers so we
14541454
# know which identifier was the macro name.
@@ -1470,22 +1470,22 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
14701470
# [@foo x] ==> (vect (macrocall @foo x))
14711471
# [@foo] ==> (vect (macrocall @foo))
14721472
# @var"#" a ==> (macrocall (var @#) a)
1473-
# A.@x y ==> (macrocall (. A (quote @x)) y)
1474-
# A.@var"#" a ==> (macrocall (. A (quote (var @#))) a)
1473+
# A.@x y ==> (macrocall (. A @x) y)
1474+
# A.@var"#" a ==> (macrocall (. A (var @#)) a)
14751475
# @+x y ==> (macrocall @+ x y)
1476-
# A.@.x ==> (macrocall (. A (quote @.)) x)
1476+
# A.@.x ==> (macrocall (. A @.) x)
14771477
fix_macro_name_kind!(ps, macro_name_position)
14781478
let ps = with_space_sensitive(ps)
14791479
# Space separated macro arguments
1480-
# A.@foo a b ==> (macrocall (. A (quote @foo)) a b)
1481-
# @A.foo a b ==> (macrocall (. A (quote @foo)) a b)
1480+
# A.@foo a b ==> (macrocall (. A @foo) a b)
1481+
# @A.foo a b ==> (macrocall (. A @foo) a b)
14821482
n_args = parse_space_separated_exprs(ps)
14831483
is_doc_macro = peek_behind(ps, macro_name_position).orig_kind == K"doc"
14841484
if is_doc_macro && n_args == 1
14851485
# Parse extended @doc args on next line
14861486
# @doc x\ny ==> (macrocall @doc x y)
1487-
# A.@doc x\ny ==> (macrocall (. A (quote @doc)) doc x y)
1488-
# @A.doc x\ny ==> (macrocall (. A (quote @doc)) doc x y)
1487+
# A.@doc x\ny ==> (macrocall (. A @doc) doc x y)
1488+
# @A.doc x\ny ==> (macrocall (. A @doc) doc x y)
14891489
# @doc x y\nz ==> (macrocall @doc x y)
14901490
#
14911491
# Excluded cases
@@ -1518,8 +1518,8 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
15181518
end
15191519
if is_macrocall
15201520
# @x(a, b) ==> (macrocall-p @x a b)
1521-
# A.@x(y) ==> (macrocall-p (. A (quote @x)) y)
1522-
# A.@x(y).z ==> (. (macrocall-p (. A (quote @x)) y) (quote z))
1521+
# A.@x(y) ==> (macrocall-p (. A @x) y)
1522+
# A.@x(y).z ==> (. (macrocall-p (. A @x) y) z)
15231523
fix_macro_name_kind!(ps, macro_name_position)
15241524
is_macrocall = false
15251525
macro_atname_range = nothing
@@ -1535,8 +1535,8 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
15351535
# @S[a,b] ==> (macrocall @S (vect a b))
15361536
# @S[a b] ==> (macrocall @S (hcat a b))
15371537
# @S[a; b] ==> (macrocall @S (vcat a b))
1538-
# A.@S[a] ==> (macrocall (. A (quote @S)) (vect a))
1539-
# @S[a].b ==> (. (macrocall @S (vect a)) (quote b))
1538+
# A.@S[a] ==> (macrocall (. A @S) (vect a))
1539+
# @S[a].b ==> (. (macrocall @S (vect a)) b)
15401540
#v1.7: @S[a ;; b] ==> (macrocall @S (ncat-2 a b))
15411541
#v1.6: @S[a ;; b] ==> (macrocall @S (error (ncat-2 a b)))
15421542
fix_macro_name_kind!(ps, macro_name_position)
@@ -1565,14 +1565,14 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
15651565
check_ncat_compat(ps, mark, ckind)
15661566
end
15671567
elseif k == K"."
1568-
# x .y ==> (. x (error-t) (quote y))
1568+
# x .y ==> (. x (error-t) y)
15691569
bump_disallowed_space(ps)
15701570
emark = position(ps)
15711571
if !isnothing(macro_atname_range)
15721572
# Allow `@` in macrocall only in first and last position
1573-
# A.B.@x ==> (macrocall (. (. A (quote B)) (quote @x)))
1574-
# @A.B.x ==> (macrocall (. (. A (quote B)) (quote @x)))
1575-
# A.@B.x ==> (macrocall (. (. A (error-t) B) (quote @x)))
1573+
# A.B.@x ==> (macrocall (. (. A B) @x))
1574+
# @A.B.x ==> (macrocall (. (. A B) @x))
1575+
# A.@B.x ==> (macrocall (. (. A B (error-t)) @x))
15761576
emit_diagnostic(ps, macro_atname_range...,
15771577
error="`@` must appear on first or last macro name component")
15781578
bump(ps, TRIVIA_FLAG, error="Unexpected `.` after macro name")
@@ -1603,28 +1603,23 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
16031603
emit(ps, m, K"quote", COLON_QUOTE)
16041604
emit(ps, mark, K".")
16051605
elseif k == K"$"
1606-
# f.$x ==> (. f (inert ($ x)))
1607-
# f.$(x+y) ==> (. f (inert ($ (call + x y))))
1608-
# A.$B.@x ==> (macrocall (. (. A (inert ($ B))) (quote @x)))
1609-
# @A.$x a ==> (macrocall (. A (inert (error x))) a)
1606+
# f.$x ==> (. f ($ x))
1607+
# f.$(x+y) ==> (. f ($ (call + x y)))
1608+
# A.$B.@x ==> (macrocall (. (. A ($ B)) @x))
1609+
# @A.$x a ==> (macrocall (. A (error x)) a)
16101610
m = position(ps)
16111611
bump(ps, TRIVIA_FLAG)
16121612
parse_atom(ps)
16131613
emit(ps, m, K"$")
16141614
macro_name_position = position(ps)
1615-
# We need `inert` rather than `quote` here for subtle reasons:
1616-
# We need the expression expander to "see through" the quote
1617-
# around the `$x` in `:(f.$x)`, so that the `$x` is expanded
1618-
# even though it's double quoted.
1619-
emit(ps, m, K"inert")
16201615
emit(ps, mark, K".")
16211616
elseif k == K"@"
16221617
# A macro call after some prefix A has been consumed
1623-
# A.@x ==> (macrocall (. A (quote @x)))
1624-
# A.@x a ==> (macrocall (. A (quote @x)) a)
1618+
# A.@x ==> (macrocall (. A @x))
1619+
# A.@x a ==> (macrocall (. A @x) a)
16251620
m = position(ps)
16261621
if is_macrocall
1627-
# @A.B.@x a ==> (macrocall (. (. A (quote B)) (quote (error-t) @x)) a)
1622+
# @A.B.@x a ==> (macrocall (. (. A B) (error-t) @x) a)
16281623
bump(ps, TRIVIA_FLAG, error="repeated `@` in macro module path")
16291624
else
16301625
bump(ps, TRIVIA_FLAG)
@@ -1633,7 +1628,6 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
16331628
parse_macro_name(ps)
16341629
macro_name_position = position(ps)
16351630
macro_atname_range = (m, position(ps))
1636-
emit(ps, m, K"quote")
16371631
emit(ps, mark, K".")
16381632
elseif k == K"'"
16391633
# TODO: Reclaim dotted postfix operators :-)
@@ -1643,12 +1637,10 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
16431637
error="the .' operator for transpose is discontinued")
16441638
else
16451639
# Field/property syntax
1646-
# f.x.y ==> (. (. f (quote x)) (quote y))
1647-
m = position(ps)
1640+
# f.x.y ==> (. (. f x) y)
16481641
parse_atom(ps, false)
16491642
macro_name_position = position(ps)
16501643
maybe_strmac_1 = true
1651-
emit(ps, m, K"quote")
16521644
emit(ps, mark, K".")
16531645
end
16541646
elseif k == K"'" && !preceding_whitespace(t)
@@ -1665,8 +1657,8 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
16651657
parse_call_arglist(ps, K"}")
16661658
if is_macrocall
16671659
# @S{a,b} ==> (macrocall S (braces a b))
1668-
# A.@S{a} ==> (macrocall (. A (quote @S)) (braces a))
1669-
# @S{a}.b ==> (. (macrocall @S (braces a)) (quote b))
1660+
# A.@S{a} ==> (macrocall (. A @S) (braces a))
1661+
# @S{a}.b ==> (. (macrocall @S (braces a)) b)
16701662
fix_macro_name_kind!(ps, macro_name_position)
16711663
emit(ps, m, K"braces")
16721664
emit(ps, mark, K"macrocall")
@@ -2118,7 +2110,7 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
21182110
# function ()(x) end ==> (function (call (tuple-p) x) (block))
21192111
emit(ps, mark, K"tuple", PARENS_FLAG)
21202112
else
2121-
# function (A).f() end ==> (function (call (. (parens A) (quote f))) (block))
2113+
# function (A).f() end ==> (function (call (. (parens A) f)) (block))
21222114
# function (:)() end ==> (function (call (parens :)) (block))
21232115
# function (x::T)() end ==> (function (call (parens (::-i x T))) (block))
21242116
# function (::T)() end ==> (function (call (parens (::-pre T))) (block))
@@ -2147,7 +2139,7 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
21472139
# Parse function argument list
21482140
# function f(x,y) end ==> (function (call f x y) (block))
21492141
# function f{T}() end ==> (function (call (curly f T)) (block))
2150-
# function A.f() end ==> (function (call (. A (quote f))) (block))
2142+
# function A.f() end ==> (function (call (. A f)) (block))
21512143
parse_call_chain(ps, mark)
21522144
if peek_behind(ps).kind != K"call"
21532145
# function f body end ==> (function (error f) (block body))

test/expr.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717
# Compatibility hack for VERSION >= v"1.4"
1818
# https://github.com/JuliaLang/julia/pull/34077
1919
@test parseatom(":true") == Expr(:quote, true)
20-
21-
# Handling of K"inert"
22-
@test parsestmt("a.\$b") == Expr(:., :a, QuoteNode(Expr(:$, :b)))
2320
end
2421

2522
@testset "Line numbers" begin
@@ -386,6 +383,16 @@
386383
Expr(:tuple, Expr(:parameters, Expr(:kw, :a, 1)))
387384
end
388385

386+
@testset "Field access syntax" begin
387+
@test parsestmt("a.b") == Expr(:., :a, QuoteNode(:b))
388+
@test parsestmt("a.\$b") == Expr(:., :a, QuoteNode(Expr(:$, :b)))
389+
@test parsestmt("a.:b") == Expr(:., :a, QuoteNode(:b))
390+
@test parsestmt("a.@b x") == Expr(:macrocall,
391+
Expr(:., :a, QuoteNode(Symbol("@b"))),
392+
LineNumberNode(1),
393+
:x)
394+
end
395+
389396
@testset "dotcall / dotted operators" begin
390397
@test parsestmt("f.(x,y)") == Expr(:., :f, Expr(:tuple, :x, :y))
391398
@test parsestmt("f.(x=1)") == Expr(:., :f, Expr(:tuple, Expr(:kw, :x, 1)))

test/parser.jl

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ tests = [
312312
"\$f(x)" => "(call (\$ f) x)"
313313
".&(x,y)" => "(call (. &) x y)"
314314
# parse_call_chain
315-
"f(a).g(b)" => "(call (. (call f a) (quote g)) b)"
316-
"\$A.@x" => "(macrocall (. (\$ A) (quote @x)))"
315+
"f(a).g(b)" => "(call (. (call f a) g) b)"
316+
"\$A.@x" => "(macrocall (. (\$ A) @x))"
317317

318318
# non-errors in space sensitive contexts
319319
"[f (x)]" => "(hcat f (parens x))"
@@ -322,25 +322,25 @@ tests = [
322322
"@foo a b" => "(macrocall @foo a b)"
323323
"@foo (x)" => "(macrocall @foo (parens x))"
324324
"@foo (x,y)" => "(macrocall @foo (tuple-p x y))"
325-
"A.@foo a b" => "(macrocall (. A (quote @foo)) a b)"
326-
"@A.foo a b" => "(macrocall (. A (quote @foo)) a b)"
325+
"A.@foo a b" => "(macrocall (. A @foo) a b)"
326+
"@A.foo a b" => "(macrocall (. A @foo) a b)"
327327
"[@foo x]" => "(vect (macrocall @foo x))"
328328
"[@foo]" => "(vect (macrocall @foo))"
329329
"@var\"#\" a" => "(macrocall (var @#) a)"
330330
"@(A) x" => "(macrocall (parens @A) x)"
331-
"A.@x y" => "(macrocall (. A (quote @x)) y)"
332-
"A.@var\"#\" a"=> "(macrocall (. A (quote (var @#))) a)"
331+
"A.@x y" => "(macrocall (. A @x) y)"
332+
"A.@var\"#\" a"=> "(macrocall (. A (var @#)) a)"
333333
"@+x y" => "(macrocall @+ x y)"
334-
"A.@.x" => "(macrocall (. A (quote @.)) x)"
334+
"A.@.x" => "(macrocall (. A @.) x)"
335335
# Macro names
336336
"@! x" => "(macrocall @! x)"
337337
"@.. x" => "(macrocall @.. x)"
338338
"@\$ y" => "(macrocall @\$ y)"
339339
"@[x] y z" => "(macrocall (error (vect x)) y z)"
340340
# Special @doc parsing rules
341341
"@doc x\ny" => "(macrocall @doc x y)"
342-
"A.@doc x\ny" => "(macrocall (. A (quote @doc)) x y)"
343-
"@A.doc x\ny" => "(macrocall (. A (quote @doc)) x y)"
342+
"A.@doc x\ny" => "(macrocall (. A @doc) x y)"
343+
"@A.doc x\ny" => "(macrocall (. A @doc) x y)"
344344
"@doc x y\nz" => "(macrocall @doc x y)"
345345
"@doc x\n\ny" => "(macrocall @doc x)"
346346
"@doc x\nend" => "(macrocall @doc x)"
@@ -352,8 +352,8 @@ tests = [
352352
"(a=1)()" => "(call (parens (= a 1)))"
353353
"f (a)" => "(call f (error-t) a)"
354354
"@x(a, b)" => "(macrocall-p @x a b)"
355-
"A.@x(y)" => "(macrocall-p (. A (quote @x)) y)"
356-
"A.@x(y).z" => "(. (macrocall-p (. A (quote @x)) y) (quote z))"
355+
"A.@x(y)" => "(macrocall-p (. A @x) y)"
356+
"A.@x(y).z" => "(. (macrocall-p (. A @x) y) z)"
357357
# do
358358
"f() do\nend" => "(do (call f) (tuple) (block))"
359359
"f() do ; body end" => "(do (call f) (tuple) (block body))"
@@ -364,8 +364,8 @@ tests = [
364364
"@S[a,b]" => "(macrocall @S (vect a b))"
365365
"@S[a b]" => "(macrocall @S (hcat a b))"
366366
"@S[a; b]" => "(macrocall @S (vcat a b))"
367-
"A.@S[a]" => "(macrocall (. A (quote @S)) (vect a))"
368-
"@S[a].b" => "(. (macrocall @S (vect a)) (quote b))"
367+
"A.@S[a]" => "(macrocall (. A @S) (vect a))"
368+
"@S[a].b" => "(. (macrocall @S (vect a)) b)"
369369
((v=v"1.7",), "@S[a ;; b]") => "(macrocall @S (ncat-2 a b))"
370370
((v=v"1.6",), "@S[a ;; b]") => "(macrocall @S (error (ncat-2 a b)))"
371371
"a[i]" => "(ref a i)"
@@ -383,9 +383,9 @@ tests = [
383383

384384
# Dotted forms
385385
# Allow `@` in macrocall only in first and last position
386-
"A.B.@x" => "(macrocall (. (. A (quote B)) (quote @x)))"
387-
"@A.B.x" => "(macrocall (. (. A (quote B)) (quote @x)))"
388-
"A.@B.x" => "(macrocall (. (. A (quote B)) (error-t) (quote @x)))"
386+
"A.B.@x" => "(macrocall (. (. A B) @x))"
387+
"@A.B.x" => "(macrocall (. (. A B) @x))"
388+
"A.@B.x" => "(macrocall (. (. A B) (error-t) @x))"
389389
"@M.(x)" => "(macrocall (dotcall @M (error-t) x))"
390390
"f.(a,b)" => "(dotcall f a b)"
391391
"f.(a=1; b=2)" => "(dotcall f (= a 1) (parameters (= b 2)))"
@@ -395,27 +395,27 @@ tests = [
395395
"A.:+" => "(. A (quote-: +))"
396396
"A.:.+" => "(. A (quote-: (. +)))"
397397
"A.: +" => "(. A (quote-: (error-t) +))"
398-
"f.\$x" => "(. f (inert (\$ x)))"
399-
"f.\$(x+y)" => "(. f (inert (\$ (parens (call-i x + y)))))"
400-
"A.\$B.@x" => "(macrocall (. (. A (inert (\$ B))) (quote @x)))"
401-
"@A.\$x a" => "(macrocall (. A (inert (error x))) a)"
402-
"A.@x" => "(macrocall (. A (quote @x)))"
403-
"A.@x a" => "(macrocall (. A (quote @x)) a)"
404-
"@A.B.@x a" => "(macrocall (. (. A (quote B)) (quote (error-t) @x)) a)"
398+
"f.\$x" => "(. f (\$ x))"
399+
"f.\$(x+y)" => "(. f (\$ (parens (call-i x + y))))"
400+
"A.\$B.@x" => "(macrocall (. (. A (\$ B)) @x))"
401+
"@A.\$x a" => "(macrocall (. A (error x)) a)"
402+
"A.@x" => "(macrocall (. A @x))"
403+
"A.@x a" => "(macrocall (. A @x) a)"
404+
"@A.B.@x a" => "(macrocall (. (. A B) (error-t) @x) a)"
405405
# .' discontinued
406406
"f.'" => "(wrapper f (error-t '))"
407407
# Field/property syntax
408-
"f.x.y" => "(. (. f (quote x)) (quote y))"
409-
"x .y" => "(. x (error-t) (quote y))"
408+
"f.x.y" => "(. (. f x) y)"
409+
"x .y" => "(. x (error-t) y)"
410410
# Adjoint
411411
"f'" => "(call-post f ')"
412412
"f'ᵀ" => "(call-post f 'ᵀ)"
413413
# Curly calls
414414
"S {a}" => "(curly S (error-t) a)"
415-
"A.@S{a}" => "(macrocall (. A (quote @S)) (braces a))"
415+
"A.@S{a}" => "(macrocall (. A @S) (braces a))"
416416
"@S{a,b}" => "(macrocall @S (braces a b))"
417-
"A.@S{a}" => "(macrocall (. A (quote @S)) (braces a))"
418-
"@S{a}.b" => "(. (macrocall @S (braces a)) (quote b))"
417+
"A.@S{a}" => "(macrocall (. A @S) (braces a))"
418+
"@S{a}.b" => "(. (macrocall @S (braces a)) b)"
419419
"S{a,b}" => "(curly S a b)"
420420
# String macros
421421
"x\"str\"" => """(macrocall @x_str (string-r "str"))"""
@@ -554,7 +554,7 @@ tests = [
554554
"function (x=1) end" => "(function (tuple-p (= x 1)) (block))"
555555
"function (;x=1) end" => "(function (tuple-p (parameters (= x 1))) (block))"
556556
"function ()(x) end" => "(function (call (tuple-p) x) (block))"
557-
"function (A).f() end" => "(function (call (. (parens A) (quote f))) (block))"
557+
"function (A).f() end" => "(function (call (. (parens A) f)) (block))"
558558
"function (:)() end" => "(function (call (parens :)) (block))"
559559
"function (x::T)() end"=> "(function (call (parens (::-i x T))) (block))"
560560
"function (::g(x))() end" => "(function (call (parens (::-pre (call g x)))) (block))"
@@ -575,7 +575,7 @@ tests = [
575575
# Function argument list
576576
"function f(x,y) end" => "(function (call f x y) (block))"
577577
"function f{T}() end" => "(function (call (curly f T)) (block))"
578-
"function A.f() end" => "(function (call (. A (quote f))) (block))"
578+
"function A.f() end" => "(function (call (. A f)) (block))"
579579
"function f body end" => "(function (error f) (block body))"
580580
"function f()::T end" => "(function (::-i (call f) T) (block))"
581581
"function f()::g(T) end" => "(function (::-i (call f) (call g T)) (block))"

0 commit comments

Comments
 (0)