I am getting odd warnings about pattern matching when compiling the following code (it is from a Phoenix controller, but as the warning doesn’t have anything to do with Phoenix, I posted this in the generic questions section):
# Edit case for editing user's password
def do_edit(conn, %{
"user" =>
%{
"type" => "password",
"old_password" => old_password,
"password" => _
} = params
}) do
user = AuthUtils.get_current_user(conn)
password_changeset = User.password_changeset(user, params)
with {:old_pass, true} <- {:old_pass, AuthUtils.check_user_password(user, old_password)},
{:updated, %User{}} <- {:updated, AuthUtils.update_user(password_changeset)} do
conn
|> put_flash(:success, "Password changed.")
|> redirect(to: Routes.preferences_path(conn, :edit))
else
err ->
error_changeset =
case err do
{:old_pass, false} ->
# We need to add an action to the changeset so that Phoenix will display the error,
# otherwise it will think the changeset was not processed (as it has not been passed
# to any Repo call) and will not show the errors
%{password_changeset | action: :update}
|> Ecto.Changeset.add_error(:old_password, "does not match your current password")
{:updated, cset} ->
cset
end
conn
|> common_edit_assigns()
|> put_flash(:error, "Error changing password.")
|> render("preferences.html", pass_changeset: error_changeset)
end
end
The case statement inside the with’s else block gets the following warnings:
warning: this clause cannot match because of different types/sizes
lib/code_stats_web/controllers/preferences_controller.ex:67
warning: this clause cannot match because of different types/sizes
lib/code_stats_web/controllers/preferences_controller.ex:74
The lines refer to the {:old_pass, false} ->
and {:updated, cset} ->
. But I know that they do match and the code works. The function AuthUtils.check_user_password/2
returns a boolean, and AuthUtils.update_user/1
returns either a User struct or a changeset.
If I hover over the clauses in VSCode, it tells me that the first clause can never match {:updated, <changeset>}
and the second clause can never match {:old_pass, false}
, but that makes no sense to me (as the opposite clauses match those!).
Now to be clear, I’m not looking for advice how to structure the code better. I am simply wondering why the warnings are given. I cannot see the problem in the match.