blob: b5ae0fe49fcedc8fa76a66793cfe0cb1f08b4571 [file] [log] [blame]
/*
* 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 + ")";
}
}