Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/elixir/pages/references/unicode-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Make sure all characters in the identifier resolve to a single script or a highl
restrictive script. See https://hexdocs.pm/elixir/unicode-syntax.html for more information.
```

Finally, Elixir will also warn on confusable identifiers in the same file. For example, Elixir will emit a warning if you use both variables `а` (Cyrillic) and `а` (Latin) in your code.
Finally, Elixir will also warn of confusable identifiers in the same file. For example, Elixir will emit a warning if you use both variables `а` (Cyrillic) and `а` (Latin) in your code.

That's the overall introduction of how Unicode is used in Elixir identifiers. In a nutshell, its goal is to support different writing systems in use today while keeping the Elixir language itself clear and secure.

Expand Down Expand Up @@ -124,13 +124,13 @@ For instance, the 'HANGUL FILLER' (`ㅤ`) character, which is often invisible, i

### C2. Confusable detection

Elixir will warn on identifiers that look the same, but aren't. Examples: in `а = a = 1`, the two 'a' characters are Cyrillic and Latin, and could be confused for each other; in `力 = カ = 1`, both are Japanese, but different codepoints, in different scripts of that writing system. Confusable identifiers can lead to hard-to-catch bugs (say, due to copy-pasted code) and can be unsafe, so we will warn about identifiers within a single file that could be confused with each other.
Elixir will warn of identifiers that look the same, but aren't. Examples: in `а = a = 1`, the two 'a' characters are Cyrillic and Latin, and could be confused for each other; in `力 = カ = 1`, both are Japanese, but different codepoints, in different scripts of that writing system. Confusable identifiers can lead to hard-to-catch bugs (say, due to copy-pasted code) and can be unsafe, so we will warn of identifiers within a single file that could be confused with each other.

We use the means described in Section 4, 'Confusable Detection', with one noted modification:

> Alternatively, it shall declare that it uses a modification, and provide a precise list of character mappings that are added to or removed from the provided ones.

Elixir will not warn on confusability for identifiers made up exclusively of characters in a-z, A-Z, 0-9, and _. This is because ASCII identifiers have existed for so long that the programming community has had their own means of dealing with confusability between identifiers like `l,1` or `O,0` (for instance, fonts designed for programming usually make it easy to differentiate between those characters).
Elixir will not warn about confusability for identifiers made up exclusively of characters in a-z, A-Z, 0-9, and _. This is because ASCII identifiers have existed for so long that the programming community has had their own means of dealing with confusability between identifiers like `l,1` or `O,0` (for instance, fonts designed for programming usually make it easy to differentiate between those characters).

### C3. Mixed Script Detection

Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/src/elixir_parser.yrl
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ matched_op_expr -> comp_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> rel_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> arrow_op_eol matched_expr : {'$1', '$2'}.

%% We warn exclusively for |> and friends because they are used
%% We warn exclusively of |> and friends because they are used
%% in other languages with lower precedence than function application,
%% which can be the source of confusion.
matched_op_expr -> arrow_op_eol no_parens_one_expr : warn_pipe('$1', '$2'), {'$1', '$2'}.
Expand Down
62 changes: 31 additions & 31 deletions lib/elixir/test/elixir/kernel/impl_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ defmodule Kernel.ImplTest do
end
end

test "warns about undefined module, but does not warn at @impl line" do
test "warns of undefined module, but does not warn at @impl line" do
capture_err =
capture_err(fn ->
Code.eval_string("""
Expand All @@ -142,7 +142,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Abc\""
end

test "warns about undefined behaviour, but does not warn at @impl line" do
test "warns of undefined behaviour, but does not warn at @impl line" do
capture_err =
capture_err(fn ->
Code.eval_string("""
Expand All @@ -162,7 +162,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Abc\""
end

test "warns for callbacks without impl and @impl has been set before" do
test "warns of callbacks without impl and @impl has been set before" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -179,7 +179,7 @@ defmodule Kernel.ImplTest do
"module attribute @impl was not set for macro bar/0 callback (specified in Kernel.ImplTest.MacroBehaviour)"
end

test "warns for callbacks without impl and @impl has been set after" do
test "warns of callbacks without impl and @impl has been set after" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand Down Expand Up @@ -220,7 +220,7 @@ defmodule Kernel.ImplTest do
end) =~ "module attribute @impl was set but no definition follows it"
end

test "warns for @impl true and no behaviour" do
test "warns of @impl true and no behaviour" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -231,7 +231,7 @@ defmodule Kernel.ImplTest do
end) =~ "got \"@impl true\" for function foo/0 but no behaviour was declared"
end

test "warns for @impl true with callback name not in behaviour" do
test "warns of @impl true with callback name not in behaviour" do
message =
capture_err(fn ->
Code.eval_string("""
Expand All @@ -250,7 +250,7 @@ defmodule Kernel.ImplTest do
assert message =~ "* Kernel.ImplTest.Behaviour.foo/0 (function)"
end

test "warns for @impl true with macro callback name not in behaviour" do
test "warns of @impl true with macro callback name not in behaviour" do
message =
capture_err(fn ->
Code.eval_string("""
Expand All @@ -269,7 +269,7 @@ defmodule Kernel.ImplTest do
assert message =~ "* Kernel.ImplTest.MacroBehaviour.bar/0 (macro)"
end

test "warns for @impl true with callback kind not in behaviour" do
test "warns of @impl true with callback kind not in behaviour" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -282,7 +282,7 @@ defmodule Kernel.ImplTest do
"got \"@impl true\" for function foo/0 but no behaviour specifies such callback"
end

test "warns for @impl true with wrong arity" do
test "warns of @impl true with wrong arity" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -295,7 +295,7 @@ defmodule Kernel.ImplTest do
"got \"@impl true\" for function foo/1 but no behaviour specifies such callback"
end

test "warns for @impl false and there are no callbacks" do
test "warns of @impl false and there are no callbacks" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -306,7 +306,7 @@ defmodule Kernel.ImplTest do
end) =~ "got \"@impl false\" for function baz/1 but no behaviour was declared"
end

test "warns for @impl false and it is a callback" do
test "warns of @impl false and it is a callback" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -319,7 +319,7 @@ defmodule Kernel.ImplTest do
"got \"@impl false\" for function foo/0 but it is a callback specified in Kernel.ImplTest.Behaviour"
end

test "warns for @impl module and no behaviour" do
test "warns of @impl module and no behaviour" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -331,7 +331,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Kernel.ImplTest.Behaviour\" for function foo/0 but no behaviour was declared"
end

test "warns for @impl module with callback name not in behaviour" do
test "warns of @impl module with callback name not in behaviour" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -344,7 +344,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Kernel.ImplTest.Behaviour\" for function bar/0 but Kernel.ImplTest.Behaviour does not specify such callback"
end

test "warns for @impl module with macro callback name not in behaviour" do
test "warns of @impl module with macro callback name not in behaviour" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -357,7 +357,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Kernel.ImplTest.MacroBehaviour\" for macro foo/0 but Kernel.ImplTest.MacroBehaviour does not specify such callback"
end

test "warns for @impl module with macro callback kind not in behaviour" do
test "warns of @impl module with macro callback kind not in behaviour" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -370,7 +370,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Kernel.ImplTest.MacroBehaviour\" for function foo/0 but Kernel.ImplTest.MacroBehaviour does not specify such callback"
end

test "warns for @impl module and callback belongs to another known module" do
test "warns of @impl module and callback belongs to another known module" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -384,7 +384,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Kernel.ImplTest.Behaviour\" for function bar/0 but Kernel.ImplTest.Behaviour does not specify such callback"
end

test "warns for @impl module and callback belongs to another unknown module" do
test "warns of @impl module and callback belongs to another unknown module" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -397,7 +397,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Kernel.ImplTest.MacroBehaviour\" for function bar/0 but this behaviour was not declared with @behaviour"
end

test "does not warn for @impl when the function with default conforms with several typespecs" do
test "does not warn of @impl when the function with default conforms with several typespecs" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.Behaviour
Expand All @@ -409,7 +409,7 @@ defmodule Kernel.ImplTest do
""")
end

test "does not warn for @impl when the function conforms to behaviour but has default value for arg" do
test "does not warn of @impl when the function conforms to behaviour but has default value for arg" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.BehaviourWithArgument
Expand All @@ -420,7 +420,7 @@ defmodule Kernel.ImplTest do
""")
end

test "does not warn for @impl when the function conforms to behaviour but has additional trailing default args" do
test "does not warn of @impl when the function conforms to behaviour but has additional trailing default args" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.BehaviourWithArgument
Expand All @@ -431,7 +431,7 @@ defmodule Kernel.ImplTest do
""")
end

test "does not warn for @impl when the function conforms to behaviour but has additional leading default args" do
test "does not warn of @impl when the function conforms to behaviour but has additional leading default args" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.BehaviourWithArgument
Expand All @@ -442,7 +442,7 @@ defmodule Kernel.ImplTest do
""")
end

test "does not warn for @impl when the function has more args than callback, but they're all defaulted" do
test "does not warn of @impl when the function has more args than callback, but they're all defaulted" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.BehaviourWithArgument
Expand All @@ -453,7 +453,7 @@ defmodule Kernel.ImplTest do
""")
end

test "does not warn for @impl with defaults when the same function is defined multiple times" do
test "does not warn of @impl with defaults when the same function is defined multiple times" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.BehaviourWithArgument
Expand All @@ -468,7 +468,7 @@ defmodule Kernel.ImplTest do
""")
end

test "does not warn for no @impl when overriding callback" do
test "does not warn of no @impl when overriding callback" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.Behaviour
Expand All @@ -482,7 +482,7 @@ defmodule Kernel.ImplTest do
""")
end

test "does not warn for overridable function missing @impl" do
test "does not warn of overridable function missing @impl" do
Code.eval_string(~S"""
defmodule Kernel.ImplTest.ImplAttributes do
@behaviour Kernel.ImplTest.Behaviour
Expand All @@ -497,7 +497,7 @@ defmodule Kernel.ImplTest do
""")
end

test "warns correctly for missing @impl only for end-user implemented function" do
test "warns correctly of missing @impl only for end-user implemented function" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -518,7 +518,7 @@ defmodule Kernel.ImplTest do
"module attribute @impl was not set for function foo/0 callback (specified in Kernel.ImplTest.Behaviour)"
end

test "warns correctly for incorrect @impl in overridable callback" do
test "warns correctly of incorrect @impl in overridable callback" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -538,7 +538,7 @@ defmodule Kernel.ImplTest do
"got \"@impl Kernel.ImplTest.MacroBehaviour\" for function foo/0 but Kernel.ImplTest.MacroBehaviour does not specify such callback"
end

test "warns only for non-generated functions in non-generated @impl" do
test "warns only of non-generated functions in non-generated @impl" do
message =
capture_err(fn ->
Code.eval_string("""
Expand All @@ -565,7 +565,7 @@ defmodule Kernel.ImplTest do
refute message =~ "foo_without_impl/0"
end

test "warns only for non-generated functions in non-generated @impl in protocols" do
test "warns only of non-generated functions in non-generated @impl in protocols" do
message =
capture_err(fn ->
Code.eval_string("""
Expand All @@ -583,7 +583,7 @@ defmodule Kernel.ImplTest do
"module attribute @impl was not set for function bar/1 callback"
end

test "warns only for generated functions in generated @impl" do
test "warns only of generated functions in generated @impl" do
message =
capture_err(fn ->
Code.eval_string("""
Expand All @@ -598,7 +598,7 @@ defmodule Kernel.ImplTest do
refute message =~ "foo_with_impl/0"
end

test "does not warn for overridable callback when using __before_compile__/1 hook" do
test "does not warn of overridable callback when using __before_compile__/1 hook" do
Code.eval_string(~S"""
defmodule BeforeCompile do
defmacro __before_compile__(_) do
Expand Down
14 changes: 7 additions & 7 deletions lib/elixir/test/elixir/kernel/warning_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ defmodule Kernel.WarningTest do
end

describe "unnecessary quotes" do
test "does not warn for unnecessary quotes in uppercase atoms/keywords" do
test "does not warn of unnecessary quotes in uppercase atoms/keywords" do
assert capture_eval(~s/:"Foo"/) == ""
assert capture_eval(~s/["Foo": :bar]/) == ""
assert capture_eval(~s/:"Foo"/) == ""
Expand All @@ -187,7 +187,7 @@ defmodule Kernel.WarningTest do
assert capture_eval(~s/:"3L1X1R"/) == ""
end

test "warns for unnecessary quotes" do
test "warns of unnecessary quotes" do
assert_warn_eval(
["nofile:1:1", "found quoted atom \"foo\" but the quotes are not required"],
~s/:"foo"/
Expand All @@ -206,7 +206,7 @@ defmodule Kernel.WarningTest do
end

describe "deprecated single quotes in atoms" do
test "warns for single quotes in atoms" do
test "warns of single quotes in atoms" do
assert_warn_eval(
[
"nofile:1:1",
Expand All @@ -216,7 +216,7 @@ defmodule Kernel.WarningTest do
)
end

test "warns twice for single and unnecessary atom quotes" do
test "warns twice of single and unnecessary atom quotes" do
assert_warn_eval(
[
"nofile:1:1",
Expand All @@ -228,7 +228,7 @@ defmodule Kernel.WarningTest do
)
end

test "warns twice for single and unnecessary call quotes" do
test "warns twice of single and unnecessary call quotes" do
assert_warn_eval(
[
"nofile:1:9",
Expand Down Expand Up @@ -1029,7 +1029,7 @@ defmodule Kernel.WarningTest do
purge(Sample)
end

test "late function heads do not warn for meta programming" do
test "late function heads do not warn of meta programming" do
assert capture_eval("""
defmodule Sample1 do
defmacro __using__(_) do
Expand Down Expand Up @@ -1532,7 +1532,7 @@ defmodule Kernel.WarningTest do
purge(Sample)
end

test "ungrouped defs do not warn for meta programming" do
test "ungrouped defs do not warn of meta programming" do
assert capture_eval("""
defmodule Sample do
for atom <- [:foo, :bar] do
Expand Down
Loading