diff --git a/src/binaryen.ts b/src/binaryen.ts
index ecaf5ac4..25236db9 100644
--- a/src/binaryen.ts
+++ b/src/binaryen.ts
@@ -440,23 +440,27 @@ export class Module {
     }
   }
 
-  createCall(target: BinaryenFunctionRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
+  createCall(target: string, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
     if (this.noEmit) return 0;
+    const cStr: CString = allocString(target);
     const cArr: CArray<i32> = allocI32Array(operands);
     try {
-      return _BinaryenCall(this.ref, target, cArr, operands.length, returnType);
+      return _BinaryenCall(this.ref, cStr, cArr, operands.length, returnType);
     } finally {
       _free(cArr);
+      _free(cStr);
     }
   }
 
-  createCallImport(target: BinaryenImportRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
+  createCallImport(target: string, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
     if (this.noEmit) return 0;
+    const cStr: CString = allocString(target);
     const cArr: CArray<i32> = allocI32Array(operands);
     try {
-      return _BinaryenCallImport(this.ref, target, cArr, operands.length, returnType);
+      return _BinaryenCallImport(this.ref, cStr, cArr, operands.length, returnType);
     } finally {
       _free(cArr);
+      _free(cStr);
     }
   }
 
diff --git a/src/compiler.ts b/src/compiler.ts
index d9cee56c..982805f8 100644
--- a/src/compiler.ts
+++ b/src/compiler.ts
@@ -1,9 +1,9 @@
 import { Module, MemorySegment, UnaryOp, BinaryOp, HostOp, Type as BinaryenType, Relooper } from "./binaryen";
 import { PATH_DELIMITER } from "./constants";
 import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
-import { Program, ClassPrototype, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
+import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
 import { CharCode, I64, U64, normalizePath, sb } from "./util";
-import { Token } from "./tokenizer";
+import { Token, Range } from "./tokenizer";
 import {
 
   Node,
@@ -376,18 +376,21 @@ export class Compiler extends DiagnosticEmitter {
     const element: Element | null = <Element | null>this.program.elements.get(internalName);
     if (!element || element.kind != ElementKind.FUNCTION_PROTOTYPE)
       throw new Error("unexpected missing function");
-    const resolvedTypeArguments: Type[] | null = this.program.resolveTypeArguments(declaration.typeParameters, typeArguments, contextualTypeArguments, alternativeReportNode); // reports
-    if (!resolvedTypeArguments)
-      return;
-    this.compileFunction(<FunctionPrototype>element, resolvedTypeArguments, contextualTypeArguments);
+    this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode);
   }
 
-  compileFunction(template: FunctionPrototype, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null): void {
-    const instance: Function | null = template.resolve(typeArguments, contextualTypeArguments);
-    if (!instance || instance.compiled)
+  compileFunctionUsingTypeArguments(prototype: FunctionPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null) {
+    const instance: Function | null = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode); // reports
+    if (!instance)
+      return;
+    this.compileFunction(instance);
+  }
+
+  compileFunction(instance: Function): void {
+    if (instance.compiled)
       return;
 
-    const declaration: FunctionDeclaration | null = template.declaration;
+    const declaration: FunctionDeclaration | null = instance.template.declaration;
     if (!declaration) // TODO: compile builtins
       throw new Error("not implemented");
 
@@ -470,7 +473,7 @@ export class Compiler extends DiagnosticEmitter {
 
         case ElementKind.CLASS_PROTOTYPE:
           if ((noTreeShaking || (<ClassPrototype>element).isExport) && !(<ClassPrototype>element).isGeneric)
-            this.compileClass(<ClassPrototype>element, []);
+            this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
           break;
 
         case ElementKind.ENUM:
@@ -479,7 +482,7 @@ export class Compiler extends DiagnosticEmitter {
 
         case ElementKind.FUNCTION_PROTOTYPE:
           if ((noTreeShaking || (<FunctionPrototype>element).isExport) && !(<FunctionPrototype>element).isGeneric)
-            this.compileFunction(<FunctionPrototype>element, []);
+            this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
           break;
 
         case ElementKind.GLOBAL:
@@ -508,7 +511,7 @@ export class Compiler extends DiagnosticEmitter {
 
         case ElementKind.CLASS_PROTOTYPE:
           if (!(<ClassPrototype>element).isGeneric)
-            this.compileClass(<ClassPrototype>element, []);
+            this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
           break;
 
         case ElementKind.ENUM:
@@ -517,7 +520,7 @@ export class Compiler extends DiagnosticEmitter {
 
         case ElementKind.FUNCTION_PROTOTYPE:
           if (!(<FunctionPrototype>element).isGeneric)
-            this.compileFunction(<FunctionPrototype>element, []);
+            this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
           break;
 
         case ElementKind.GLOBAL:
@@ -538,13 +541,17 @@ export class Compiler extends DiagnosticEmitter {
     const element: Element | null = <Element | null>this.program.elements.get(internalName);
     if (!element || element.kind != ElementKind.CLASS_PROTOTYPE)
       throw new Error("unexpected missing class");
-    const resolvedTypeArguments: Type[] | null = this.program.resolveTypeArguments(declaration.typeParameters, typeArguments, contextualTypeArguments, alternativeReportNode); // reports
-    if (!resolvedTypeArguments)
-      return;
-    this.compileClass(<ClassPrototype>element, resolvedTypeArguments, contextualTypeArguments);
+    this.compileClassUsingTypeArguments(<ClassPrototype>element, typeArguments, contextualTypeArguments, alternativeReportNode);
   }
 
-  compileClass(cls: ClassPrototype, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null) {
+  compileClassUsingTypeArguments(prototype: ClassPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
+    const instance: Class | null = prototype.resolveInclTypeArguments(typeArguments, contextualTypeArguments, alternativeReportNode);
+    if (!instance)
+      return;
+    this.compileClass(instance);
+  }
+
+  compileClass(cls: Class) {
     throw new Error("not implemented");
   }
 
@@ -1319,14 +1326,46 @@ export class Compiler extends DiagnosticEmitter {
     const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
     if (!element)
       return this.module.createUnreachable();
-    if (element.kind != ElementKind.FUNCTION_PROTOTYPE) {
-      // TODO: report 'Cannot invoke an expression whose type lacks a call signature.'
+    if (element.kind == ElementKind.FUNCTION_PROTOTYPE) {
+      const functionInstance: Function | null = (<FunctionPrototype>element).resolveInclTypeArguments(expression.typeArguments, this.currentFunction.contextualTypeArguments, expression); // reports
+      if (!functionInstance)
+        return this.module.createUnreachable();
+      return this.compileCall(functionInstance, expression.arguments, expression);
+    }
+    this.error(DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, expression.range, element.internalName);
+    return this.module.createUnreachable();
+  }
+
+  compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): BinaryenExpressionRef {
+    if (!functionInstance.compiled)
+      this.compileFunction(functionInstance);
+    const parameters: Parameter[] = functionInstance.parameters;
+    let k: i32 = parameters.length;
+    if (argumentExpressions.length > k) {
+      this.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, k.toString(10), argumentExpressions.length.toString(10));
       return this.module.createUnreachable();
     }
-    throw new Error("not implemented");
+    const operands: BinaryenExpressionRef[] = new Array(k);
+    for (let i: i32 = 0; i < k; ++i) {
+      if (argumentExpressions.length > i) {
+        operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type);
+      } else {
+        const initializer: Expression | null = parameters[i].initializer;
+        if (initializer) {
+          operands[i] = this.compileExpression(initializer, parameters[i].type);
+        } else {
+          this.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range, (i + 1).toString(10), argumentExpressions.length.toString(10));
+          return this.module.createUnreachable();
+        }
+      }
+    }
+    return this.module.createCall(functionInstance.internalName, operands, typeToBinaryenType(functionInstance.returnType));
   }
 
   compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): BinaryenExpressionRef {
+    const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
+    if (!element)
+      return this.module.createUnreachable();
     throw new Error("not implemented");
   }
 
diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts
index 1c870a6f..42c7af2c 100644
--- a/src/diagnosticMessages.generated.ts
+++ b/src/diagnosticMessages.generated.ts
@@ -52,12 +52,15 @@ export enum DiagnosticCode {
   Type_0_is_not_assignable_to_type_1 = 2322,
   _this_cannot_be_referenced_in_current_location = 2332,
   Property_0_does_not_exist_on_type_1 = 2339,
+  Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures = 2349,
   The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
   The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
   Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
   Duplicate_function_implementation = 2393,
   Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
   The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
+  Expected_0_arguments_but_got_1 = 2554,
+  Expected_at_least_0_arguments_but_got_1 = 2555,
   Expected_0_type_arguments_but_got_1 = 2558,
   File_0_not_found = 6054
 }
@@ -115,12 +118,15 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
     case 2322: return "Type '{0}' is not assignable to type '{1}'.";
     case 2332: return "'this' cannot be referenced in current location.";
     case 2339: return "Property '{0}' does not exist on type '{1}'.";
+    case 2349: return "Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.";
     case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
     case 2364: return "The left-hand side of an assignment expression must be a variable or a property access.";
     case 2391: return "Function implementation is missing or not immediately following the declaration.";
     case 2393: return "Duplicate function implementation.";
     case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
     case 2541: return "The target of an assignment must be a variable or a property access.";
+    case 2554: return "Expected {0} arguments, but got {1}.";
+    case 2555: return "Expected at least {0} arguments, but got {1}.";
     case 2558: return "Expected {0} type arguments, but got {1}.";
     case 6054: return "File '{0}' not found.";
     default: return "";
diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json
index 76f9c690..3c9bc79f 100644
--- a/src/diagnosticMessages.json
+++ b/src/diagnosticMessages.json
@@ -52,12 +52,15 @@
   "Type '{0}' is not assignable to type '{1}'.": 2322,
   "'this' cannot be referenced in current location.": 2332,
   "Property '{0}' does not exist on type '{1}'.": 2339,
+  "Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.": 2349,
   "The operand of an increment or decrement operator must be a variable or a property access.": 2357,
   "The left-hand side of an assignment expression must be a variable or a property access.": 2364,
   "Function implementation is missing or not immediately following the declaration.": 2391,
   "Duplicate function implementation.": 2393,
   "Export declaration conflicts with exported declaration of '{0}'.": 2484,
   "The target of an assignment must be a variable or a property access.": 2541,
+  "Expected {0} arguments, but got {1}.": 2554,
+  "Expected at least {0} arguments, but got {1}.": 2555,
   "Expected {0} type arguments, but got {1}.": 2558,
 
   "File '{0}' not found.": 6054
diff --git a/src/program.ts b/src/program.ts
index ad5cf91d..c93e8cf7 100644
--- a/src/program.ts
+++ b/src/program.ts
@@ -508,19 +508,19 @@ export class Program extends DiagnosticEmitter {
     return null;
   }
 
-  resolveTypeArguments(typeParameters: TypeParameter[], typeArgumentNodes: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Type[] | null {
+  resolveTypeArguments(typeParameters: TypeParameter[], typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Type[] | null {
     const parameterCount: i32 = typeParameters.length;
-    const argumentCount: i32 = typeArgumentNodes.length;
+    const argumentCount: i32 = typeArgumentNodes ? typeArgumentNodes.length : 0;
     if (parameterCount != argumentCount) {
       if (argumentCount)
-        this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, Range.join(typeArgumentNodes[0].range, typeArgumentNodes[argumentCount - 1].range), parameterCount.toString(10), argumentCount.toString(10));
+        this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, Range.join((<TypeNode[]>typeArgumentNodes)[0].range, (<TypeNode[]>typeArgumentNodes)[argumentCount - 1].range), parameterCount.toString(10), argumentCount.toString(10));
       else if (alternativeReportNode)
         this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, alternativeReportNode.range.atEnd, parameterCount.toString(10), "0");
       return null;
     }
     const typeArguments: Type[] = new Array(parameterCount);
     for (let i: i32 = 0; i < parameterCount; ++i) {
-      const type: Type | null = this.resolveType(typeArgumentNodes[i], contextualTypeArguments, true); // reports
+      const type: Type | null = this.resolveType((<TypeNode[]>typeArgumentNodes)[i], contextualTypeArguments, true); // reports
       if (!type)
         return null;
       // TODO: check extendsType
@@ -531,7 +531,7 @@ export class Program extends DiagnosticEmitter {
 
   resolveElement(expression: Expression, contextualFunction: Function): Element | null {
 
-    // this
+    // this -> Class
     if (expression.kind == NodeKind.THIS) {
       if (contextualFunction.instanceMethodOf)
         return contextualFunction.instanceMethodOf;
@@ -539,6 +539,8 @@ export class Program extends DiagnosticEmitter {
       return null;
     }
 
+    let ret: Element;
+
     // local or global name
     if (expression.kind == NodeKind.IDENTIFIER) {
       const name: string = (<IdentifierExpression>expression).name;
@@ -557,10 +559,10 @@ export class Program extends DiagnosticEmitter {
     // static or instance property (incl. enum values) or method
     } else if (expression.kind == NodeKind.PROPERTYACCESS) {
       const target: Element | null = this.resolveElement((<PropertyAccessExpression>expression).expression, contextualFunction); // reports
-      let member: Element | null = null;
       if (!target)
         return null;
       const propertyName: string = (<PropertyAccessExpression>expression).property.name;
+      let member: Element | null = null;
       if (target.kind == ElementKind.ENUM)
         member = <EnumValue | null>(<Enum>target).members.get(propertyName);
       else if (target.kind == ElementKind.CLASS_PROTOTYPE)
@@ -702,10 +704,12 @@ export class Parameter {
 
   name: string;
   type: Type;
+  initializer: Expression | null;
 
-  constructor(name: string, type: Type) {
+  constructor(name: string, type: Type, initializer: Expression | null = null) {
     this.name = name;
     this.type = type;
+    this.initializer = initializer;
   }
 }
 
@@ -802,26 +806,51 @@ export class FunctionPrototype extends Element {
     this.instances.set(instanceKey, instance);
     return instance;
   }
+
+  resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Function | null {
+    let resolvedTypeArguments: Type[] | null;
+    if (this.isGeneric) {
+      if (!this.declaration)
+        throw new Error("not implemented"); // generic builtin
+      resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
+      if (!resolvedTypeArguments)
+        return null;
+    } else {
+      // TODO: check typeArgumentNodes being empty
+      resolvedTypeArguments = [];
+    }
+    return this.resolve(resolvedTypeArguments, contextualTypeArguments);
+  }
 }
 
 /** A resolved function. */
 export class Function extends Element {
 
   kind = ElementKind.FUNCTION;
-  template: FunctionPrototype;
-  typeArguments: Type[];
-  parameters: Parameter[];
-  returnType: Type;
-  instanceMethodOf: Class | null;
-  locals: Map<string,Local> = new Map();
-  additionalLocals: Type[] = []; // without parameters
-  breakContext: string | null = null;
 
+  /** Underlying function template. */
+  template: FunctionPrototype;
+  /** Concrete type arguments. */
+  typeArguments: Type[];
+  /** Concrete function parameters. */
+  parameters: Parameter[];
+  /** Concrete return type. */
+  returnType: Type;
+  /** If a method, the concrete class it is a member of. */
+  instanceMethodOf: Class | null;
+  /** Map of locals by name. */
+  locals: Map<string,Local> = new Map();
+  /** List of additional non-parameter locals. */
+  additionalLocals: Type[] = [];
+  /** Current break context label. */
+  breakContext: string | null = null;
+  /** Contextual type arguments. */
   contextualTypeArguments: Map<string,Type> = new Map();
 
   private breakMajor: i32 = 0;
   private breakMinor: i32 = 0;
 
+  /** Constructs a new concrete function. */
   constructor(template: FunctionPrototype, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: Class | null) {
     super(template.program, internalName);
     this.template = template;
@@ -841,8 +870,10 @@ export class Function extends Element {
     }
   }
 
+  /** Tests if this function is an instance method. */
   get isInstance(): bool { return this.instanceMethodOf != null; }
 
+  /** Adds a local of the specified type, with an optional name. */
   addLocal(type: Type, name: string | null = null): Local {
     // if it has a name, check previously as this method will throw otherwise
     let localIndex = this.parameters.length + this.additionalLocals.length;
@@ -857,12 +888,14 @@ export class Function extends Element {
     return local;
   }
 
+  /** Enters a(nother) break context. */
   enterBreakContext(): string {
     if (!this.breakMinor)
       this.breakMajor++;
     return this.breakContext = this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
   }
 
+  /** Leaves the current break context. */
   leaveBreakContext(): void {
     if (--this.breakMinor < 0)
       throw new Error("unexpected unbalanced break context");
@@ -931,6 +964,21 @@ export class ClassPrototype extends Namespace {
       throw new Error("unexpected instantiation of internal class");
     throw new Error("not implemented");
   }
+
+  resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Class | null {
+    let resolvedTypeArguments: Type[] | null;
+    if (this.isGeneric) {
+      if (!this.declaration)
+        throw new Error("not implemented"); // generic builtin
+      resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
+      if (!resolvedTypeArguments)
+        return null;
+    } else {
+      // TODO: check typeArgumentNodes being empty
+      resolvedTypeArguments = [];
+    }
+    return this.resolve(resolvedTypeArguments, contextualTypeArguments);
+  }
 }
 
 /** A resolved class. */