ZenCode compiler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FunctionHeader.zs 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import .expression.CallArguments;
  2. import .expression.Expression;
  3. import .generic.TypeParameter;
  4. import .scope.TypeScope;
  5. import .type.BasicTypeID;
  6. import .type.GlobalTypeRegistry;
  7. import .type.ITypeID;
  8. import .type.member.LocalMemberCache;
  9. /**
  10. *
  11. * @author Hoofdgebruiker
  12. */
  13. public class FunctionHeader {
  14. static val NO_PARAMETERS as FunctionParameter[] = new FunctionParameter[](0);
  15. static val NO_TYPE_PARAMETERS as TypeParameter[] = new TypeParameter[](0);
  16. val typeParameters as TypeParameter[] : get;
  17. val returnType as ITypeID : get;
  18. val parameters as FunctionParameter[] : get;
  19. val thrownType as ITypeID : get;
  20. public this(returnType as ITypeID) {
  21. this.typeParameters = NO_TYPE_PARAMETERS;
  22. this.returnType = returnType;
  23. this.parameters = NO_PARAMETERS;
  24. this.thrownType = BasicTypeID.VOID;
  25. }
  26. public this(returnType as ITypeID, parameters... as ITypeID) {
  27. this.typeParameters = NO_TYPE_PARAMETERS;
  28. this.returnType = returnType;
  29. this.parameters = parameters.map(parameter => new FunctionParameter(parameter, null));
  30. this.thrownType = BasicTypeID.VOID;
  31. }
  32. public this(returnType as ITypeID, parameters... as FunctionParameter) {
  33. this.typeParameters = NO_TYPE_PARAMETERS;
  34. this.returnType = returnType;
  35. this.parameters = parameters;
  36. this.thrownType = BasicTypeID.VOID;
  37. }
  38. public this(typeParameters as TypeParameter[], returnType as ITypeID, thrownType as ITypeID, parameters... as FunctionParameter) {
  39. this.typeParameters = typeParameters;
  40. this.returnType = returnType;
  41. this.parameters = parameters;
  42. this.thrownType = thrownType;
  43. }
  44. public get numberOfTypeParameters as int
  45. => typeParameters.length;
  46. public get doesThrow as bool
  47. => thrownType != BasicTypeID.VOID;
  48. public instance(registry as GlobalTypeRegistry, mapping as ITypeID[TypeParameter]) as FunctionHeader {
  49. val genericParameters = this.typeParameters.map(parameter => parameter.withGenericArguments(registry, mapping));
  50. val returnType = this.returnType.withGenericArguments(registry, mapping);
  51. val parameters = this.parameters.map(parameter => parameter.withGenericArguments(registry, mapping));
  52. val thrownType = this.thrownType.withGenericArguments(registry, mapping);
  53. return new FunctionHeader(genericParameters, returnType, thrownType, parameters);
  54. }
  55. public inferTypes(cache as LocalMemberCache, arguments as CallArguments, resultHint as ITypeID[]) as ITypeID[]? {
  56. if arguments.arguments.length != this.parameters.length
  57. return null;
  58. val mapping = new ITypeID[TypeParameter];
  59. if !resultHint.empty {
  60. val temp = new ITypeID[TypeParameter];
  61. for hint in resultHint {
  62. if returnType.inferTypeParameters(cache, hint, temp) {
  63. mapping = temp;
  64. break;
  65. }
  66. }
  67. }
  68. // TODO: lambda header inference
  69. for i, parameter in parameters
  70. if !parameter.type.inferTypeParameters(cache, argument.arguments[i].type, mapping)
  71. return null;
  72. if mapping.size > typeParameters.length
  73. return null;
  74. val result = new ITypeID[](typeParameters.length);
  75. for i, typeParameter in typeParameters {
  76. if typeParameter !in mapping
  77. return null;
  78. result[i] = mapping[typeParameter];
  79. }
  80. return result;
  81. }
  82. public hasInferenceBlockingTypeParameters(parameters as TypeParameter[]) as bool
  83. => this.parameters
  84. .contains((i, parameter) => parameter.type.hasInferenceBlockingTypeParameters(parameters));
  85. public canCastTo(scope as TypeScope, header as FunctionHeader) as bool {
  86. if parameters.length != header.parameters.length
  87. return false; // TODO: check type argument compatibility
  88. if !scope.getTypeMembers(returnType).canCastImplicit(header.returnType)
  89. return false;
  90. return !parameters.contains((i, parameter)
  91. => !scope.getTypeMembers(header.parameters[i].type).canCastImplicit(parameter.type));
  92. }
  93. public accepts(scope as TypeScope, arguments... as Expression) as bool {
  94. if parameters.length != arguments.length
  95. return false;
  96. return !arguments.contains((i, argument) => !scope
  97. .getTypeMembers(argument.type)
  98. .canCastImplicit(parameters[i].type));
  99. }
  100. /**
  101. * Checks if two function headers are equivalent. Functions headers are
  102. * equivalent if their types are the same.
  103. *
  104. * @param other
  105. * @return
  106. */
  107. public isEquivalentTo(other as FunctionHeader) as bool {
  108. if parameters.length != other.parameters.length
  109. return false;
  110. return !parameters.contains((i, parameter) => parameter.type !== other.parameters[i].type);
  111. }
  112. /**
  113. * Checks if two function headers are similar. "similar" means that there
  114. * exists a set of parameters for which there is no way to determine which
  115. * one to call.
  116. *
  117. * Note that this does not mean that there is never confusion about which
  118. * method to call. There can be confusion due to implicit conversions. This
  119. * can be resolved by performing the conversions explicitly.
  120. *
  121. * It is illegal to have two similar methods with the same name.
  122. *
  123. * @param other
  124. * @return
  125. */
  126. public isSimilarTo(other as FunctionHeader) as bool {
  127. val common = int.min(parameters.length, other.parameters.length);
  128. for i in 0 .. common
  129. if parameters[i].type !== other.parameters[i].type
  130. return false;
  131. for i in common .. parameters.length
  132. if parameters[i].defaultValue == null
  133. return false;
  134. for i in common .. other.parameters.length
  135. if other.parameters[i].defaultValue == null
  136. return false;
  137. return true;
  138. }
  139. public withGenericArguments(registry as GlobalTypeRegistry, arguments as ITypeID[TypeParameter]) as FunctionHeader {
  140. val returnType = this.returnType.withGenericArguments(registry, arguments);
  141. val parameters = this.parameters.map(parameter => {
  142. val modified = parameter.type.withGenericArguments(registry, arguments);
  143. return modified == parameter.type ? parameter : new FunctionParameter(modified, parameter.name);
  144. });
  145. return new FunctionHeader(
  146. typeParameters,
  147. returnType,
  148. thrownType.withGenericArguments(registry, arguments),
  149. parameters);
  150. }
  151. public withGenericArguments(registry as GlobalTypeRegistry, arguments as ITypeID[]) as FunctionHeader {
  152. val typeArguments = new ITypeID[TypeParameter];
  153. for i, typeParameter in typeParameters
  154. typeArguments[typeParameter] = arguments[i];
  155. return withGenericArguments(registry, typeArguments);
  156. }
  157. public forTypeParameterInference() as FunctionHeader {
  158. return new FunctionHeader(BasicTypeID.UNDETERMINED, parameters);
  159. }
  160. public forLambda(lambdaHeader as FunctionHeader) as FunctionHeader {
  161. val parameters = lambdaHeader.parameters
  162. .map((i, parameter) => new FunctionParameter(this.parameters[i].type, parameter.name));
  163. return new FunctionHeader(typeParameters, returnType, thrownType, parameters);
  164. }
  165. public getVariadicParameter() as FunctionParameter?
  166. => !parameters.empty && parameters.last.variadic ? parameters.last : null;
  167. public explainWhyIncompatible(scope as TypeScope, arguments as CallArguments) as string {
  168. if this.parameters.length != arguments.arguments.length
  169. return parameters.length + " parameters expected but " + arguments.arguments.length + " given.";
  170. if numberOfTypeParameters != arguments.numberOfTypeArguments
  171. return numberOfTypeParameters + " type parameters expected but " + arguments.numberOfTypeArguments + " given.";
  172. for i, parameter in parameters
  173. if !scope.getTypeMembers(arguments.arguments[i].type).canCastImplicit(parameter.type)
  174. return "Parameter " + i + ": cannot cast " + arguments.arguments[i].type + " to " + parameter.type;
  175. return "Method should be compatible";
  176. }
  177. public as string {
  178. val result = new StringBuilder();
  179. if typeParameters.length > 0
  180. result << '<' << typeParameters.map(param => param as string).join(', ') << '>';
  181. result << '(' << parameters.map(parameter => parameter as string).join(', ') < ')';
  182. return result as string;
  183. }
  184. }