| Index: lib/merge.ts | 
| diff --git a/lib/merge.ts b/lib/merge.ts | 
| index 0b9c8d746496b1608dd7eb08d7b35a25735520ed..49180029a4467d5b680f36e0e183f9e4a1567df0 100644 | 
| --- a/lib/merge.ts | 
| +++ b/lib/merge.ts | 
| @@ -14,12 +14,18 @@ export class MergedType { | 
| if (t) { | 
| // TODO(jacobr): get a better unique name for a type. | 
| switch (t.kind) { | 
| +        case ts.SyntaxKind.NullKeyword: | 
| +          // No need to include the null type as all Dart types are nullable anyway. | 
| +          return; | 
| case ts.SyntaxKind.UnionType: | 
| let union = <ts.UnionTypeNode>t; | 
| union.types.forEach(this.merge.bind(this)); | 
| return; | 
| -        case ts.SyntaxKind.LastTypeNode: | 
| -          this.merge((t as ts.ParenthesizedTypeNode).type); | 
| +        case ts.SyntaxKind.IntersectionType: | 
| +          // Arbitrarily pick the first type of the intersection type as the merged type. | 
| +          // TODO(jacobr): re-evaluate this logic. | 
| +          let intersection = <ts.IntersectionTypeNode>t; | 
| +          this.merge(intersection.types[0]); | 
| return; | 
| case ts.SyntaxKind.TypePredicate: | 
| this.merge((t as ts.TypePredicateNode).type); | 
| @@ -31,19 +37,21 @@ export class MergedType { | 
| let decl = this.fc.getDeclaration(typeRef.typeName); | 
| if (decl !== null && decl.kind === ts.SyntaxKind.TypeAliasDeclaration) { | 
| let alias = <ts.TypeAliasDeclaration>decl; | 
| +            if (!base.supportedAliasType(alias)) { | 
| +              if (typeRef.typeArguments) { | 
| +                console.log( | 
| +                    'Warning: typeReference with arguements not supported yet:' + t.getText()); | 
| +              } | 
|  | 
| -            if (typeRef.typeArguments) { | 
| -              throw 'TypeReference with arguements not supported yet:' + t.getText(); | 
| +              this.merge(alias.type); | 
| } | 
| - | 
| -            this.merge(alias.type); | 
| return; | 
| } | 
| break; | 
| default: | 
| break; | 
| } | 
| -      this.types[this.fc.generateDartTypeName(t, true)] = t; | 
| +      this.types[this.fc.generateDartTypeName(t, {insideComment: true})] = t; | 
| } | 
| } | 
|  | 
| @@ -109,9 +117,91 @@ export class MergedParameter { | 
| } | 
|  | 
| /** | 
| + * Handle a parameter that is the result of merging parameter declarations from | 
| + * multiple method overloads. | 
| + */ | 
| +export class MergedTypeParameter { | 
| +  constructor(param: ts.TypeParameterDeclaration, fc: FacadeConverter) { | 
| +    this.constraint = new MergedType(fc); | 
| +    this.textRange = param; | 
| +    this.merge(param); | 
| +    this.name = base.ident(param.name); | 
| +  } | 
| + | 
| +  merge(param: ts.TypeParameterDeclaration) { | 
| +    this.constraint.merge(param.constraint); | 
| +    // We ignore param.expression as it is not supported by Dart. | 
| +  } | 
| + | 
| +  toTypeParameterDeclaration(): ts.TypeParameterDeclaration { | 
| +    let ret = <ts.TypeParameterDeclaration>ts.createNode(ts.SyntaxKind.TypeParameter); | 
| +    let nameIdentifier = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier); | 
| +    nameIdentifier.text = this.name; | 
| +    ret.name = nameIdentifier; | 
| +    base.copyLocation(this.textRange, ret); | 
| +    let constraint = this.constraint.toTypeNode(); | 
| +    // TODO(jacobr): remove this check once we have support for union types within comments. | 
| +    // We can't currently handle union types in merged type parameters as the comments for type | 
| +    // parameters in function types are not there for documentation and impact strong mode. | 
| +    if (constraint && constraint.kind !== ts.SyntaxKind.UnionType) { | 
| +      ret.constraint = constraint; | 
| +    } | 
| +    return ret; | 
| +  } | 
| + | 
| +  private name: string; | 
| +  private constraint: MergedType; | 
| +  private textRange: ts.TextRange; | 
| +} | 
| + | 
| +/** | 
| + * Handle a parameter that is the result of merging parameter declarations from | 
| + * multiple method overloads. | 
| + */ | 
| +export class MergedTypeParameters { | 
| +  private mergedParameters: {[s: string]: MergedTypeParameter} = {}; | 
| +  private textRange: ts.TextRange; | 
| + | 
| +  constructor(private fc: FacadeConverter) {} | 
| + | 
| +  merge(params: ts.NodeArray<ts.TypeParameterDeclaration>) { | 
| +    if (!params) return; | 
| +    if (!this.textRange) { | 
| +      this.textRange = params; | 
| +    } | 
| +    for (let i = 0; i < params.length; i++) { | 
| +      let param = params[i]; | 
| +      let name = base.ident(param.name); | 
| +      if (Object.hasOwnProperty.call(this.mergedParameters, name)) { | 
| +        let merged = this.mergedParameters[name]; | 
| +        if (merged) { | 
| +          merged.merge(param); | 
| +        } | 
| +      } else { | 
| +        this.mergedParameters[name] = new MergedTypeParameter(param, this.fc); | 
| +      } | 
| +    } | 
| +  } | 
| + | 
| +  toTypeParameters(): ts.NodeArray<ts.TypeParameterDeclaration> { | 
| +    let names = Object.getOwnPropertyNames(this.mergedParameters); | 
| +    if (names.length === 0) { | 
| +      return undefined; | 
| +    } | 
| + | 
| +    let ret = [] as ts.NodeArray<ts.TypeParameterDeclaration>; | 
| +    base.copyLocation(this.textRange, ret); | 
| +    for (let i = 0; i < names.length; ++i) { | 
| +      ret.push(this.mergedParameters[names[i]].toTypeParameterDeclaration()); | 
| +    } | 
| +    return ret; | 
| +  } | 
| +} | 
| + | 
| +/** | 
| * Normalize a SourceFile | 
| */ | 
| -export function normalizeSourceFile(f: ts.SourceFile) { | 
| +export function normalizeSourceFile(f: ts.SourceFile, fc: FacadeConverter) { | 
| let modules: {[name: string]: ts.ModuleDeclaration} = {}; | 
|  | 
| // Merge top level modules. | 
| @@ -120,7 +210,7 @@ export function normalizeSourceFile(f: ts.SourceFile) { | 
| if (statement.kind !== ts.SyntaxKind.ModuleDeclaration) continue; | 
| let moduleDecl = <ts.ModuleDeclaration>statement; | 
| let name = moduleDecl.name.text; | 
| -    if (modules.hasOwnProperty(name)) { | 
| +    if (Object.hasOwnProperty.call(modules, name)) { | 
| let srcBody = modules[name].body; | 
| let srcBodyBlock: ts.ModuleBlock; | 
|  | 
| @@ -162,13 +252,78 @@ export function normalizeSourceFile(f: ts.SourceFile) { | 
| declaration: ts.VariableDeclaration) { | 
| if (declaration.name.kind === ts.SyntaxKind.Identifier) { | 
| let name: string = (<ts.Identifier>(declaration.name)).text; | 
| -            if (classes.hasOwnProperty(name)) { | 
| +            let existingClass = Object.hasOwnProperty.call(classes, name); | 
| +            let hasConstructor = false; | 
| +            if (declaration.type) { | 
| +              let type: ts.TypeNode = declaration.type; | 
| +              if (type.kind === ts.SyntaxKind.TypeLiteral) { | 
| +                let literal = <ts.TypeLiteralNode>type; | 
| +                hasConstructor = literal.members.some((member: ts.Node) => { | 
| +                  return member.kind === ts.SyntaxKind.ConstructSignature; | 
| +                }); | 
| +              } else if (type.kind === ts.SyntaxKind.TypeReference) { | 
| +                // Handle interfaces with constructors. As Dart does not support calling arbitrary | 
| +                // functions like constructors we need to upgrade the interface to be a class | 
| +                // so we call invoke the constructor on the interface class. | 
| +                // Example typescript library definition matching this pattern: | 
| +                // | 
| +                // interface XStatic { | 
| +                //   new (a: string, b): XStatic; | 
| +                //   foo(); | 
| +                // } | 
| +                // | 
| +                // declare var X: XStatic; | 
| +                // | 
| +                // In JavaScript you could just write new X() and create an | 
| +                // instance of XStatic. We don't | 
| +                let typeRef = type as ts.TypeReferenceNode; | 
| +                let typeName = typeRef.typeName; | 
| +                let symbol = fc.tc.getSymbolAtLocation(typeName); | 
| +                if (symbol == null) return; | 
| +                let decl = fc.getSymbolDeclaration(symbol, typeName); | 
| +                if (decl == null) return; | 
| +                if (decl.kind !== ts.SyntaxKind.InterfaceDeclaration) return; | 
| +                let interfaceDecl = decl as base.ExtendedInterfaceDeclaration; | 
| +                if (!interfaceDecl.members.some( | 
| +                        (member) => { return member.kind === ts.SyntaxKind.ConstructSignature; })) | 
| +                  return; | 
| + | 
| +                if (interfaceDecl.classLikeVariableDeclaration == null) { | 
| +                  // We could add extra logic to be safer such as only infering that variable names | 
| +                  // are class like for cases where variable names are UpperCamelCase matching JS | 
| +                  // conventions that a variable is a Class definition. | 
| +                  interfaceDecl.classLikeVariableDeclaration = declaration; | 
| +                } | 
| +              } | 
| +            } | 
| + | 
| +            if (existingClass || hasConstructor) { | 
| +              if (!existingClass) { | 
| +                // Create a stub existing class to upgrade the object literal to if there is not an | 
| +                // existing class with the same name. | 
| +                let clazz = <ts.ClassDeclaration>ts.createNode(ts.SyntaxKind.ClassDeclaration); | 
| +                base.copyLocation(declaration, clazz); | 
| +                clazz.name = declaration.name as ts.Identifier; | 
| +                clazz.members = <ts.NodeArray<ts.ClassElement>>[]; | 
| +                base.copyLocation(declaration, clazz.members); | 
| +                replaceNode(n, clazz); | 
| +                classes[name] = clazz; | 
| +              } | 
| + | 
| let existing = classes[name]; | 
| +              if (existing.kind === ts.SyntaxKind.InterfaceDeclaration) { | 
| +                let interfaceDecl = existing as base.ExtendedInterfaceDeclaration; | 
| +                // It is completely safe to assume that we know the precise class like variable | 
| +                // declaration for the interface in this case as they have the same exact name. | 
| +                interfaceDecl.classLikeVariableDeclaration = declaration; | 
| +              } | 
| let members = existing.members as Array<ts.ClassElement>; | 
| if (declaration.type) { | 
| let type: ts.TypeNode = declaration.type; | 
| if (type.kind === ts.SyntaxKind.TypeLiteral) { | 
| -                  removeNode(n); | 
| +                  if (existingClass) { | 
| +                    removeNode(n); | 
| +                  } | 
| let literal = <ts.TypeLiteralNode>type; | 
| literal.members.forEach((member: ts.Node) => { | 
| switch (member.kind) { | 
| @@ -249,37 +404,29 @@ export function normalizeSourceFile(f: ts.SourceFile) { | 
| } | 
| } | 
|  | 
| -  function makeCallableClassesImplementFunction(decl: base.ClassLike) { | 
| -    if (base.isCallable(decl)) { | 
| -      // Modify the AST to explicitly state that the class implements Function | 
| -      if (!decl.heritageClauses) { | 
| -        decl.heritageClauses = <ts.NodeArray<ts.HeritageClause>>[]; | 
| -        base.copyLocation(decl, decl.heritageClauses); | 
| -      } | 
| -      let clauses = decl.heritageClauses; | 
| -      let clause = base.arrayFindPolyfill( | 
| -          clauses, (c) => c.token !== ts.SyntaxKind.ExtendsKeyword || | 
| -              decl.kind === ts.SyntaxKind.InterfaceDeclaration); | 
| -      if (clause == null) { | 
| -        clause = <ts.HeritageClause>ts.createNode(ts.SyntaxKind.HeritageClause); | 
| -        clause.token = decl.kind === ts.SyntaxKind.InterfaceDeclaration ? | 
| -            ts.SyntaxKind.ExtendsKeyword : | 
| -            ts.SyntaxKind.ImplementsKeyword; | 
| -        clause.types = <ts.NodeArray<ts.ExpressionWithTypeArguments>>[]; | 
| -        clause.parent = decl; | 
| -        base.copyLocation(decl, clause); | 
| -        clauses.push(clause); | 
| +  function replaceInArray(nodes: ts.NodeArray<ts.Node>, v: ts.Node, replacement: ts.Node) { | 
| +    for (let i = 0, len = nodes.length; i < len; ++i) { | 
| +      if (nodes[i] === v) { | 
| +        nodes[i] = replacement; | 
| +        break; | 
| } | 
| -      let functionType = | 
| -          <ts.ExpressionWithTypeArguments>ts.createNode(ts.SyntaxKind.ExpressionWithTypeArguments); | 
| -      functionType.parent = clause; | 
| -      base.copyLocation(clause, functionType); | 
| -      let fn = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier); | 
| -      fn.text = 'Function'; | 
| -      fn.parent = functionType; | 
| -      base.copyLocation(functionType, fn); | 
| -      functionType.expression = fn; | 
| -      clause.types.push(functionType); | 
| +    } | 
| +  } | 
| + | 
| +  function replaceNode(n: ts.Node, replacement: ts.Node) { | 
| +    let parent = n.parent; | 
| +    replacement.parent = parent; | 
| +    switch (parent.kind) { | 
| +      case ts.SyntaxKind.ModuleBlock: | 
| +        let block = <ts.ModuleBlock>parent; | 
| +        replaceInArray(block.statements, n, replacement); | 
| +        break; | 
| +      case ts.SyntaxKind.SourceFile: | 
| +        let sourceFile = <ts.SourceFile>parent; | 
| +        replaceInArray(sourceFile.statements, n, replacement); | 
| +        break; | 
| +      default: | 
| +        throw 'replaceNode not implemented for kind:' + parent.kind; | 
| } | 
| } | 
|  | 
| @@ -291,7 +438,7 @@ export function normalizeSourceFile(f: ts.SourceFile) { | 
| let name = classDecl.name.text; | 
| // TODO(jacobr): validate that the classes have consistent | 
| // modifiers, etc. | 
| -        if (classes.hasOwnProperty(name)) { | 
| +        if (Object.hasOwnProperty.call(classes, name)) { | 
| let existing = classes[name]; | 
| (classDecl.members as Array<ts.ClassElement>).forEach((e: ts.ClassElement) => { | 
| (existing.members as Array<ts.ClassElement>).push(e); | 
| @@ -301,7 +448,6 @@ export function normalizeSourceFile(f: ts.SourceFile) { | 
| } else { | 
| classes[name] = classDecl; | 
| // Perform other class level post processing here. | 
| -          makeCallableClassesImplementFunction(classDecl); | 
| } | 
| break; | 
| case ts.SyntaxKind.ModuleDeclaration: | 
|  |