/* * Copyright (C) 2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; class CallExpression extends Expression { constructor(origin, name, typeArguments, argumentList) { super(origin); this._name = name; this._typeArguments = typeArguments; this._argumentList = argumentList; this.func = null; this._isCast = false; this._returnType = null; } get name() { return this._name; } get typeArguments() { return this._typeArguments; } get argumentList() { return this._argumentList; } get isCast() { return this._isCast; } get returnType() { return this._returnType; } static resolve(origin, possibleOverloads, typeParametersInScope, name, typeArguments, argumentList, argumentTypes, returnType) { let call = new CallExpression(origin, name, typeArguments, argumentList); call.argumentTypes = argumentTypes.map(argument => argument.visit(new AutoWrapper())); call.possibleOverloads = possibleOverloads; if (returnType) call.setCastData(returnType); return {call, resultType: call.resolve(possibleOverloads, typeParametersInScope, typeArguments)}; } resolve(possibleOverloads, typeParametersInScope, typeArguments) { if (!possibleOverloads) throw new WTypeError(this.origin.originString, "Did not find any functions named " + this.name); let overload = null; let failures = []; for (let typeParameter of typeParametersInScope) { if (!(typeParameter instanceof TypeVariable)) continue; if (!typeParameter.protocol) continue; let signatures = typeParameter.protocol.protocolDecl.signaturesByNameWithTypeVariable(this.name, typeParameter); if (!signatures) continue; overload = resolveOverloadImpl(signatures, this.typeArguments, this.argumentTypes, this.returnType); if (overload.func) break; failures.push(...overload.failures); overload = null; } if (!overload) { overload = resolveOverloadImpl( possibleOverloads, this.typeArguments, this.argumentTypes, this.returnType); if (!overload.func) { failures.push(...overload.failures); let message = "Did not find function named " + this.name + " for call with "; if (this.typeArguments.length) message += "type arguments <" + this.typeArguments + "> and "; message += "argument types (" + this.argumentTypes + ")"; if (this.returnType) message +=" and return type " + this.returnType; if (failures.length) message += ", but considered:\n" + failures.join("\n") throw new WTypeError(this.origin.originString, message); } } for (let i = 0; i < typeArguments.length; ++i) { let typeArgumentType = typeArguments[i]; let typeParameter = overload.func.typeParameters[i]; if (!(typeParameter instanceof ConstexprTypeParameter)) continue; if (!typeParameter.type.equalsWithCommit(typeArgumentType)) throw new Error("At " + this.origin.originString + " constexpr type argument and parameter types not equal: argument = " + typeArgumentType + ", parameter = " + typeParameter.type); } for (let i = 0; i < this.argumentTypes.length; ++i) { let argumentType = this.argumentTypes[i]; let parameterType = overload.func.parameters[i].type.substituteToUnification( overload.func.typeParameters, overload.unificationContext); let result = argumentType.equalsWithCommit(parameterType); if (!result) throw new Error("At " + this.origin.originString + " argument and parameter types not equal after type argument substitution: argument = " + argumentType + ", parameter = " + parameterType); } return this.resolveToOverload(overload); } resolveToOverload(overload) { this.func = overload.func; this.actualTypeArguments = overload.typeArguments.map(typeArgument => typeArgument instanceof Type ? typeArgument.visit(new AutoWrapper()) : typeArgument); this.instantiatedActualTypeArguments = this.actualTypeArguments; let result = overload.func.returnType.substituteToUnification( overload.func.typeParameters, overload.unificationContext); if (!result) throw new Error("Null return type"); result = result.visit(new AutoWrapper()); this.resultType = result; return result; } becomeCast(returnType) { this._returnType = new TypeRef(this.origin, this.name, this._typeArguments); this._returnType.type = returnType; this._name = "operator cast"; this._isCast = true; this._typeArguments = []; } setCastData(returnType) { this._returnType = returnType; this._isCast = true; } toString() { return (this.isCast ? "operator " + this.returnType : this.name) + "<" + this.typeArguments + ">" + (this.actualTypeArguments ? "<<" + this.actualTypeArguments + ">>" : "") + "(" + this.argumentList + ")"; } }