Cannot understand warnings in Gradient

Background

I am now trying Gradual type checking, as a consequence I am giving a shot to Gradient. As I see it, this is an alternative to Dialyzer.

Problems

So, on my first ever code snippet, I started with a pure function:

defmodule TipCalculator do

  @spec getTipPercentage(List[String.t()]) :: non_neg_integer
  def getTipPercentage(names) do
    names_size = length(names)

    cond do
      names_size > 5 -> 20
      names_size > 0 -> 10
      true -> 0
    end
  end
end

From my point of view, my type checks are rather solid.
However, Gradient seems to have a different opinion:

===> Analyzing applications...
===> Compiling gradualizer
src/gradualizer.erl:45:2: Warning: opaque type top() is underspecified and therefore meaningless

src/typechecker.erl:3234:1: Warning: function type_check_cons_in/4 is unused
src/typechecker.erl:3247:1: Warning: function type_check_cons_union/4 is unused
src/typechecker.erl:4612:1: Warning: function verbose/3 is unused
src/typechecker.erl:4870:1: Warning: function gen_partition/3 is unused
src/typechecker.erl:4872:1: Warning: function paux/3 is unused

==> gradient
Compiling 14 files (.ex)
Generated gradient app
==> grokking_fp
Compiling 1 file (.ex)
warning: code block contains unused literal "\n" (remove the literal or assign it to _ to avoid warnings)
  lib/tip_calculator.ex: TipCalculator

Generated grokking_fp app
Typechecking files...
lib/tip_calculator.ex: Undefined remote type Access:get/2 on line 0

From what I can understand, this one piece of code (from a fresh project) has several issues:

  1. warning: code block contains unused literal “\n” (remove the literal or assign it to _ to avoid warnings)
  2. lib/tip_calculator.ex: Undefined remote type Access:get/2 on line 0

The fist one sounds like a warning credo (or a linter) would give me. So I am not really sure what do do with it. I am expecting a tool that does type checks only (maybe I am wrong?).

The second one, I have no idea.

Questions

What am I doing wrong?

This looks suspect for me. Looks like Python type annotations. What you want in Elixir typespecs is [String.t()]. I think list(String.t()) may work as well.

Worth noting that your first warning is coming at compile time, so probably not from Gradient at all.

You are correct. I got confused a little bit, the correct typing was [String.t].
I will say however that:

lib/tip_calculator.ex: Undefined remote type Access:get/2 on line 0

Is not (to me) a very descriptive error message.
However, given the alternative (dialzyer) message is not much better:

lib/tip_calculator.ex:8:unknown_type
Unknown type: Access.get/2.

I will say however, the line number was an incredible help to find the issue.
With Gradient line 0 really threw me off.

I think the error message is that because x[y] is translated by the compiler to an Access.get(x, y) call and that’s what is then seen by the tools: a type Access.get/2 with two arguments. It rightly complains that such a type is not defined. Don’t know why Gradient loses the line information, though.

1 Like

I have created an issue in the tool’s repository:

Let’s see what the author’s opinion on the issue is.