@Override
  public void visitPyParameterList(final @NotNull PyParameterList paramlist) {
    final LanguageLevel languageLevel = LanguageLevel.forElement(paramlist);
    ParamHelper.walkDownParamArray(
      paramlist.getParameters(),
      new ParamHelper.ParamVisitor() {
        final Set<String> parameterNames = new HashSet<>();
        boolean hadPositionalContainer = false;
        boolean hadKeywordContainer = false;
        boolean hadDefaultValue = false;
        boolean hadSlash = false;
        boolean hadSingleStar = false;
        boolean hadParamsAfterSingleStar = false;
        int inTuple = 0;
        @Override
        public void visitNamedParameter(PyNamedParameter parameter, boolean first, boolean last) {
          if (parameterNames.contains(parameter.getName())) {
            markError(parameter, PyPsiBundle.message("ANN.duplicate.param.name"));
          }
          parameterNames.add(parameter.getName());
          if (parameter.isPositionalContainer()) {
            if (hadKeywordContainer) {
              markError(parameter, PyPsiBundle.message("ANN.starred.param.after.kwparam"));
            }
            if (hadSingleStar) {
              markError(parameter, PyPsiBundle.message("ANN.multiple.args"));
            }

            if (hadPositionalContainer) markError(parameter, PyPsiBundle.message("ANN.multiple.args"));
            hadPositionalContainer = true;
          }
          else if (parameter.isKeywordContainer()) {
            if (hadKeywordContainer) markError(parameter, PyPsiBundle.message("ANN.multiple.kwargs"));
            hadKeywordContainer = true;

            if (hadSingleStar && !hadParamsAfterSingleStar) {
              markError(parameter, PyPsiBundle.message("ANN.named.parameters.after.star"));
            }
          }
          else {
            if (hadSingleStar) {
              hadParamsAfterSingleStar = true;
            }
            if (hadPositionalContainer && languageLevel.isPython2()) {
              markError(parameter, PyPsiBundle.message("ANN.regular.param.after.vararg"));
            }
            else if (hadKeywordContainer) {
              markError(parameter, PyPsiBundle.message("ANN.regular.param.after.keyword"));
            }
            if (parameter.hasDefaultValue()) {
              hadDefaultValue = true;
            }
            else {
              if (hadDefaultValue && !hadSingleStar && (languageLevel.isPython2() || !hadPositionalContainer) && inTuple == 0) {
                markError(parameter, PyPsiBundle.message("ANN.non.default.param.after.default"));
              }
            }
          }
        }

        @Override
        public void enterTupleParameter(PyTupleParameter param, boolean first, boolean last) {
          inTuple++;
          if (languageLevel.isPy3K()) {
            markError(param, PyPsiBundle.message("ANN.tuple.py3"));
          }
          else if (!param.hasDefaultValue() && hadDefaultValue) {
            markError(param, PyPsiBundle.message("ANN.non.default.param.after.default"));
          }
        }

        @Override
        public void leaveTupleParameter(PyTupleParameter param, boolean first, boolean last) {
          inTuple--;
        }

        @Override
        public void visitSlashParameter(@NotNull PySlashParameter param, boolean first, boolean last) {
          if (hadSlash) {
            markError(param, PyPsiBundle.message("ANN.multiple.slash"));
          }
          hadSlash = true;
          if (hadPositionalContainer) {
            markError(param, PyPsiBundle.message("ANN.slash.param.after.vararg"));
          }
          else if (hadKeywordContainer) {
            markError(param, PyPsiBundle.message("ANN.slash.param.after.keyword"));
          }
          if (first) {
            markError(param, PyPsiBundle.message("ANN.named.parameters.before.slash"));
          }
        }

        @Override
        public void visitSingleStarParameter(PySingleStarParameter param, boolean first, boolean last) {
          if (hadPositionalContainer || hadSingleStar) {
            markError(param, PyPsiBundle.message("ANN.multiple.args"));
          }
          hadSingleStar = true;
          if (last) {
            markError(param, PyPsiBundle.message("ANN.named.parameters.after.star"));
          }
        }
      }
    );
  }
@Override
  public void visitPyParameterList(final @NotNull PyParameterList paramlist)