visitMethodCall()

in lib/semantic.js [2464:2519]


  visitMethodCall(ast, env) {
    assert.equal(ast.left.type, 'method_call');
    const id = ast.left.id;
    const name = id.lexeme;
    const staticMethod = this.getStaticMethod(name);
    const instanceMethod = this.getInstanceMethod(name);
    const defined = staticMethod || instanceMethod;
    if (!defined) {
      this.error(`the api/function "${name}" is undefined`, id);
    }

    const { method: definedApi, module: moduleName } = defined;

    if (definedApi.type === 'api' && !env.isAsync) {
      this.error(`the api only can be used in async function`, id);
    }

    if (definedApi.type === 'function') {
      if (!env.isAsync && definedApi.isAsync) {
        this.error(`the async function only can be used in async function`, id);
      }
    }

    if (ast.args.length !== definedApi.params.params.length) {
      this.error(`the parameters are mismatched, expect ${definedApi.params.params.length} ` +
        `parameters, actual ${ast.args.length}`, id);
    }

    const expected = this.getParameterTypes(definedApi, moduleName);

    const actual = [];
    for (let i = 0; i < ast.args.length; i++) {
      const arg = ast.args[i];
      this.visitExpr(arg, env);
      const type = this.getExprType(arg, env);

      actual.push(type);
    }
    if (!eql(expected, actual)) {
      this.error(`the parameter` +
        ` types are mismatched. expected ` +
        `${name}(${expected.map((item) => display(item)).join(', ')}), but ` +
        `${name}(${actual.map((item) => display(item)).join(', ')})`, id);
    }

    for (let i = 0; i < ast.args.length; i++) {
      const arg = ast.args[i];
      arg.needCast = isNeedToMap(expected[i], arg.inferred);
      arg.expectedType = expected[i];
    }

    ast.isStatic = definedApi.type === 'api' ? false : definedApi.isStatic;
    ast.isAsync = definedApi.type === 'api' ? true : definedApi.isAsync;
    ast.inferred = this.getType(definedApi.returnType);
    ast.hasThrow = !builtin.has(name) && (ast.isAsync || definedApi.hasThrow);
  }