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);
}