Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: lib/facade_converter.ts

Issue 2394683003: JS Interop Facade generation polish.
Patch Set: more cleanup Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/declaration.ts ('k') | lib/main.ts » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 import * as ts from 'typescript'; 1 import * as ts from 'typescript';
2 2
3 import * as base from './base'; 3 import * as base from './base';
4 import {Set} from './base'; 4 import {Set, TypeDisplayOptions} from './base';
5 import {DART_LIBRARIES_FOR_BROWSER_TYPES, TS_TO_DART_TYPENAMES} from './dart_lib raries_for_browser_types'; 5 import {DART_LIBRARIES_FOR_BROWSER_TYPES, TS_TO_DART_TYPENAMES} from './dart_lib raries_for_browser_types';
6 import {Transpiler} from './main'; 6 import {Transpiler} from './main';
7 import {MergedType} from './merge'; 7 import {MergedType} from './merge';
8 8
9 type CallHandler = (c: ts.CallExpression, context: ts.Expression) => void; 9 type CallHandler = (c: ts.CallExpression, context: ts.Expression) => void;
10 type PropertyHandler = (c: ts.PropertyAccessExpression) => void; 10 type PropertyHandler = (c: ts.PropertyAccessExpression) => void;
11 11
12 const FACADE_DEBUG = false; 12 const FACADE_DEBUG = false;
13 const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//; 13 const FACADE_NODE_MODULES_PREFIX = /^(\.\.\/)*node_modules\//;
14 14
15 // These constants must be kept in sync with package:func/func.dart which 15 // These constants must be kept in sync with package:func/func.dart which
16 // provides a cannonical set of typedefs defining commonly used function types 16 // provides a cannonical set of typedefs defining commonly used function types
17 // to simplify specifying function types in Dart. 17 // to simplify specifying function types in Dart.
18 const MAX_DART_FUNC_ACTION_PARAMETERS = 4; 18 const MAX_DART_FUNC_ACTION_PARAMETERS = 4;
19 const MAX_DART_FUNC_ACTION_PARAMETERS_OPTIONAL = 1; 19 const MAX_DART_FUNC_ACTION_PARAMETERS_OPTIONAL = 1;
20 20
21 /** 21 /**
22 * Prefix to add to a variable name that leaves the JS name referenced 22 * Prefix to add to a variable name that leaves the JS name referenced
23 * unchanged. 23 * unchanged.
24 */ 24 */
25 const DART_RESERVED_NAME_PREFIX = 'JS$'; 25 export const DART_RESERVED_NAME_PREFIX = 'JS$';
26 26
27 export function fixupIdentifierName(text: string): string { 27 export function fixupIdentifierName(text: string): string {
28 return (FacadeConverter.DART_RESERVED_WORDS.indexOf(text) !== -1 || 28 return (FacadeConverter.DART_RESERVED_WORDS.indexOf(text) !== -1 ||
29 FacadeConverter.DART_OTHER_KEYWORDS.indexOf(text) !== -1 || text[0] == = '_') ? 29 FacadeConverter.DART_OTHER_KEYWORDS.indexOf(text) !== -1 || text.match (/^(\d|_)/)) ?
30 DART_RESERVED_NAME_PREFIX + text : 30 DART_RESERVED_NAME_PREFIX + text :
31 text; 31 text;
32 } 32 }
33 33
34 function numOptionalParameters(parameters: ts.NodeArray<ts.ParameterDeclaration> ): number { 34 function numOptionalParameters(parameters: ts.ParameterDeclaration[]): number {
35 for (let i = 0; i < parameters.length; ++i) { 35 for (let i = 0; i < parameters.length; ++i) {
36 if (parameters[i].questionToken) return parameters.length - i; 36 if (parameters[i].questionToken) return parameters.length - i;
37 } 37 }
38 return 0; 38 return 0;
39 } 39 }
40 40
41 function hasVarArgs(parameters: ts.NodeArray<ts.ParameterDeclaration>): boolean { 41 function hasVarArgs(parameters: ts.ParameterDeclaration[]): boolean {
42 for (let i = 0; i < parameters.length; ++i) { 42 for (let i = 0; i < parameters.length; ++i) {
43 if (parameters[i].dotDotDotToken) return true; 43 if (parameters[i].dotDotDotToken) return true;
44 } 44 }
45 return false; 45 return false;
46 } 46 }
47 47
48 /** 48 /**
49 * Generates the JavaScript expression required to reference the node 49 * Generates the JavaScript expression required to reference the node
50 * from the global context. InterfaceDeclarations do not technically correspond 50 * from the global context. InterfaceDeclarations do not technically correspond
51 * to actual JavaScript objects but we still generate a reference path for them 51 * to actual JavaScript objects but we still generate a reference path for them
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 this.dartTypes[fullPath] = ret; 154 this.dartTypes[fullPath] = ret;
155 return ret; 155 return ret;
156 } 156 }
157 i++; 157 i++;
158 } 158 }
159 } 159 }
160 160
161 lookupName(node: base.NamedDeclaration, context: ts.Node) { return this.comput eName(node).name; } 161 lookupName(node: base.NamedDeclaration, context: ts.Node) { return this.comput eName(node).name; }
162 } 162 }
163 163
164 function cloneOptions(options: TypeDisplayOptions): TypeDisplayOptions {
165 return {
166 insideComment: options.insideComment,
167 insideTypeArgument: options.insideTypeArgument,
168 hideComment: options.hideComment,
169 typeArguments: options.typeArguments,
170 resolvedTypeArguments: options.resolvedTypeArguments
171 };
172 }
173
174 function addInsideTypeArgument(options: TypeDisplayOptions): TypeDisplayOptions {
175 let ret = cloneOptions(options);
176 ret.insideTypeArgument = true;
177 return ret;
178 }
179
180 function addInsideComment(options: TypeDisplayOptions): TypeDisplayOptions {
181 let ret = cloneOptions(options);
182 ret.insideComment = true;
183 return ret;
184 }
185
186 function addHideComment(options: TypeDisplayOptions): TypeDisplayOptions {
187 let ret = cloneOptions(options);
188 ret.hideComment = true;
189 return ret;
190 }
191
192 function setTypeArguments(
193 options: TypeDisplayOptions, typeArguments: ts.TypeNode[]): TypeDisplayOptio ns {
194 let ret = cloneOptions(options);
195 ret.typeArguments = typeArguments;
196 return ret;
197 }
198
199 function resolveTypeArguments(
200 options: TypeDisplayOptions, parameters: ts.TypeParameterDeclaration[]) {
201 let ret = cloneOptions(options);
202 let typeArguments = options.typeArguments ? options.typeArguments : [];
203 ret.resolvedTypeArguments = {};
204 if (parameters) {
205 for (let i = 0; i < parameters.length; ++i) {
206 let param = parameters[i];
207 ret.resolvedTypeArguments[base.ident(param.name)] = typeArguments[i];
208 }
209 }
210 // Type arguments have been resolved forward so we don't need to emit them dir ectly.
211 ret.typeArguments = null;
212 return ret;
213 }
214
215 function removeResolvedTypeArguments(options: TypeDisplayOptions): TypeDisplayOp tions {
216 let ret = cloneOptions(options);
217 ret.resolvedTypeArguments = null;
218 return ret;
219 }
220
164 export class FacadeConverter extends base.TranspilerBase { 221 export class FacadeConverter extends base.TranspilerBase {
165 private tc: ts.TypeChecker; 222 tc: ts.TypeChecker;
166 // For the Dart keyword list see 223 // For the Dart keyword list see
167 // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords 224 // https://www.dartlang.org/docs/dart-up-and-running/ch02.html#keywords
168 static DART_RESERVED_WORDS = 225 static DART_RESERVED_WORDS =
169 ('assert break case catch class const continue default do else enum extend s false final ' + 226 ('assert break case catch class const continue default do else enum extend s false final ' +
170 'finally for if in is new null rethrow return super switch this throw tru e try let void ' + 227 'finally for if in is new null rethrow return super switch this throw tru e try let void ' +
171 'while with') 228 'while with')
172 .split(/ /); 229 .split(/ /);
173 230
174 // These are the built-in and limited keywords. 231 // These are the built-in and limited keywords.
175 static DART_OTHER_KEYWORDS = 232 static DART_OTHER_KEYWORDS =
176 ('abstract as async await deferred dynamic export external factory get imp lements import ' + 233 ('abstract as async await deferred dynamic export external factory get imp lements import ' +
177 'library operator part set static sync typedef yield call') 234 'library operator part set static sync typedef yield call')
178 .split(/ /); 235 .split(/ /);
179 236
237 // TODO(jacobr): add separate list of members of the core Dart object class an d core Dart List
238 // class that need to be escaped with JS$ when being entered as properties.
239 // As methods on Object and List will take priorty over JS subclasses.
240 // Note that toString is fine as the default implementation is compatible with JavaScript.
241 static DART_OBJECT_MEMBERS = ('hashCode, runtimeType noSuchMethod').split(/ /) ;
242
243 static DART_LIST_MEMBERS =
244 ('first hashCode isEmpty isNotEmpty iterator last length reversed runtimeT ype single add ' +
245 'addAll any asMap clear contains elementAt every expand fillRange firstWh ere fold forEach ' +
246 'getRange indexOf insert insertAll join lastIndexOf lastWhere map noSuchM ethod reduce ' +
247 'remove removeAt removeLast removeRange removeWhere replaceRange retainWh ere setAll ' +
248 'setRange shuffle singleWhere skip skipWhile sort sublist take takeWhile toList toSet ' +
249 'toString where')
250 .split(/ /);
251
180 private candidateTypes: {[typeName: string]: boolean} = {}; 252 private candidateTypes: {[typeName: string]: boolean} = {};
181 private typingsRootRegex: RegExp; 253 private typingsRootRegex: RegExp;
182 private genericMethodDeclDepth = 0; 254 private genericMethodDeclDepth = 0;
183 255
184 constructor( 256 constructor(transpiler: Transpiler, typingsRoot = '', private nameRewriter: Na meRewriter) {
185 transpiler: Transpiler, typingsRoot = '', private nameRewriter: NameRewrit er,
186 private useHtml: boolean) {
187 super(transpiler); 257 super(transpiler);
188 if (useHtml) { 258 this.extractPropertyNames(TS_TO_DART_TYPENAMES, this.candidateTypes);
189 this.extractPropertyNames(TS_TO_DART_TYPENAMES, this.candidateTypes); 259 // Remove this line if decide to support generating code that avoids dart:ht ml.
190 Object.keys(DART_LIBRARIES_FOR_BROWSER_TYPES) 260 Object.keys(DART_LIBRARIES_FOR_BROWSER_TYPES)
191 .forEach((propName) => this.candidateTypes[propName] = true); 261 .forEach((propName) => this.candidateTypes[propName] = true);
192 } else {
193 this.extractPropertyNames(TS_TO_DART_TYPENAMES, this.candidateTypes);
194 }
195 262
196 this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.')); 263 this.typingsRootRegex = new RegExp('^' + typingsRoot.replace('.', '\\.'));
197 } 264 }
198 265
199 private extractPropertyNames(m: ts.Map<ts.Map<any>>, candidates: {[k: string]: boolean}) { 266 private extractPropertyNames(m: ts.Map<ts.Map<any>>, candidates: {[k: string]: boolean}) {
200 for (let fileName of Object.keys(m)) { 267 for (let fileName of Object.keys(m)) {
201 const file = m[fileName]; 268 const file = m[fileName];
202 if (file === undefined) { 269 if (file === undefined) {
203 return; 270 return;
204 } 271 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) return false; 322 if (!t || (t.flags & ts.TypeFlags.TypeParameter) === 0) return false;
256 323
257 // Check if the symbol we're looking at is the type parameter. 324 // Check if the symbol we're looking at is the type parameter.
258 let symbol = this.tc.getSymbolAtLocation(name); 325 let symbol = this.tc.getSymbolAtLocation(name);
259 if (symbol !== t.symbol) return false; 326 if (symbol !== t.symbol) return false;
260 327
261 // Check that the Type Parameter has been declared by a function declaration . 328 // Check that the Type Parameter has been declared by a function declaration .
262 return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.Functio nDeclaration); 329 return symbol.declarations.some(d => d.parent.kind === ts.SyntaxKind.Functio nDeclaration);
263 } 330 }
264 331
265 generateTypeList(types: ts.TypeNode[], insideComment: boolean, seperator = ',' ): string { 332 generateTypeList(types: ts.TypeNode[], options: TypeDisplayOptions, seperator = ','): string {
266 let that = this; 333 let that = this;
267 return types.map((type) => { return that.generateDartTypeName(type, insideCo mment); }) 334 return types
335 .map((type) => { return that.generateDartTypeName(type, addInsideTypeArg ument(options)); })
268 .join(seperator); 336 .join(seperator);
269 } 337 }
270 338
271 maybeGenerateTypeArguments( 339 generateDartTypeName(node: ts.TypeNode, options?: TypeDisplayOptions): string {
272 n: {typeArguments?: ts.NodeArray<ts.TypeNode>}, insideComment: boolean): s tring { 340 if (!options) {
273 if (!n.typeArguments) return ''; 341 options = {
274 return '<' + this.generateTypeList(n.typeArguments, insideComment) + '>'; 342 insideComment: this.insideCodeComment,
275 } 343 insideTypeArgument: this.insideTypeArgument
344 };
345 }
276 346
277 generateDartTypeName(node: ts.TypeNode, insideComment: boolean): string {
278 let name: string; 347 let name: string;
279 let comment: string; 348 let comment: string;
280 if (!node) { 349 if (!node) {
281 return 'dynamic'; 350 return 'dynamic';
282 } 351 }
352
283 switch (node.kind) { 353 switch (node.kind) {
284 case ts.SyntaxKind.TypeQuery: 354 case ts.SyntaxKind.TypeQuery:
285 let query = <ts.TypeQueryNode>node;
286 name = 'dynamic'; 355 name = 'dynamic';
287 name += '/* Dart does not support TypeQuery: typeof ' + base.ident(query .exprName) + ' */'; 356 // TODO(jacobr): evaluate supporting this case.
357 // let query = <ts.TypeQueryNode>node;
358 // name += '/* TypeQuery: typeof ' + base.ident(query.exprName) + ' */';
288 break; 359 break;
289 case ts.SyntaxKind.LastTypeNode:
290 let type = (node as ts.ParenthesizedTypeNode).type;
291 if (!type) {
292 // This case occurs for String literal types
293 comment = node.getText();
294 // TODO(jacobr): find a better way to detect string literal types.
295 name = comment[0] === '"' ? 'String' : 'dynamic';
296 break;
297 }
298 return this.generateDartTypeName(type, insideComment);
299 case ts.SyntaxKind.TypePredicate: 360 case ts.SyntaxKind.TypePredicate:
300 return this.generateDartTypeName((node as ts.TypePredicateNode).type, in sideComment); 361 return this.generateDartTypeName((node as ts.TypePredicateNode).type, op tions);
301 case ts.SyntaxKind.TupleType: 362 case ts.SyntaxKind.TupleType:
302 let tuple = <ts.TupleTypeNode>node; 363 let tuple = <ts.TupleTypeNode>node;
303 name = 'List<'; 364 name = 'List<';
304 let mergedType = new MergedType(this); 365 let mergedType = new MergedType(this);
305 tuple.elementTypes.forEach((t) => mergedType.merge(t)); 366 tuple.elementTypes.forEach((t) => mergedType.merge(t));
306 name += this.generateDartTypeName(mergedType.toTypeNode(), insideComment ); 367 name += this.generateDartTypeName(mergedType.toTypeNode(), addInsideType Argument(options));
307 name += '>'; 368 name += '>';
308 comment = 'Tuple<' + this.generateTypeList(tuple.elementTypes, insideCom ment) + '>'; 369 // Intentionally ensure this comment is not valid Dart code so we do not use the /*=
370 // syntax and so that it is clear this isn't a true Dart code comment.
371 comment = 'Tuple of <' +
372 this.generateTypeList(tuple.elementTypes, addInsideComment(options)) + '>';
309 break; 373 break;
310 case ts.SyntaxKind.UnionType: 374 case ts.SyntaxKind.UnionType: {
311 let union = <ts.UnionTypeNode>node; 375 let union = <ts.UnionTypeNode>node;
312 // TODO(jacobr): this isn't fundamentally JS Interop specific but we 376 // TODO(jacobr): this isn't fundamentally JS Interop specific but we
313 // choose to be more aggressive at finding a useful value for the 377 // choose to be more aggressive at finding a useful value for the
314 // union when in JS Interop mode while otherwise we expect that union 378 // union when in JS Interop mode while otherwise we expect that union
315 // types will not be used extensively. 379 // types will not be used extensively.
316 let simpleType = this.toSimpleDartType(union.types); 380 let simpleType = this.toSimpleDartType(union.types);
317 if (simpleType) { 381 if (simpleType) {
318 name = this.generateDartTypeName(simpleType, insideComment); 382 name = this.generateDartTypeName(simpleType, addHideComment(options));
319 } else { 383 } else {
320 name = 'dynamic'; 384 name = 'dynamic';
321 } 385 }
322 let types = union.types; 386 let types = union.types;
323 comment = this.generateTypeList(types, true, '|'); 387 comment = this.generateTypeList(types, addInsideComment(options), '|');
324 break; 388 } break;
389 case ts.SyntaxKind.IntersectionType: {
390 let intersection = <ts.IntersectionTypeNode>node;
391 // TODO(jacobr): this isn't fundamentally JS Interop specific but we
392 // choose to be more aggressive at finding a useful value for the
393 // union when in JS Interop mode while otherwise we expect that union
394 // types will not be used extensively.
395 let simpleType = this.toSimpleDartType(intersection.types);
396 if (simpleType) {
397 name = this.generateDartTypeName(simpleType, addHideComment(options));
398 } else {
399 name = 'dynamic';
400 }
401 let types = intersection.types;
402 comment = this.generateTypeList(types, addInsideComment(options), '&');
403 } break;
325 case ts.SyntaxKind.TypePredicate: 404 case ts.SyntaxKind.TypePredicate:
326 return this.generateDartTypeName((node as ts.TypePredicateNode).type, in sideComment); 405 return this.generateDartTypeName((node as ts.TypePredicateNode).type, op tions);
327 case ts.SyntaxKind.TypeReference: 406 case ts.SyntaxKind.TypeReference:
328 let typeRef = <ts.TypeReferenceNode>node; 407 let typeRef = <ts.TypeReferenceNode>node;
329 name = this.generateDartName(typeRef.typeName, insideComment) + 408 name = this.generateDartName(
330 this.maybeGenerateTypeArguments(typeRef, insideComment); 409 typeRef.typeName, setTypeArguments(options, typeRef.typeArguments));
331 break; 410 break;
332 case ts.SyntaxKind.TypeLiteral: 411 case ts.SyntaxKind.TypeLiteral:
333 let members = (<ts.TypeLiteralNode>node).members; 412 let members = (<ts.TypeLiteralNode>node).members;
334 if (members.length === 1 && members[0].kind === ts.SyntaxKind.IndexSigna ture) { 413 if (members.length === 1 && members[0].kind === ts.SyntaxKind.IndexSigna ture) {
335 let indexSig = <ts.IndexSignatureDeclaration>(members[0]); 414 let indexSig = <ts.IndexSignatureDeclaration>(members[0]);
336 if (indexSig.parameters.length > 1) { 415 if (indexSig.parameters.length > 1) {
337 this.reportError(indexSig, 'Expected an index signature to have a si ngle parameter'); 416 this.reportError(indexSig, 'Expected an index signature to have a si ngle parameter');
338 } 417 }
339 // Unfortunately for JS interop, we cannot treat JS Objects as Dart 418 // Unfortunately for JS interop, we cannot treat JS Objects as Dart
340 // Map objects. We could treat them as JSMap<indexSig.type> 419 // Map objects. We could treat them as JSMap<indexSig.type>
341 // if we define a base JSMap type that is Map like but not actually 420 // if we define a base JSMap type that is Map like but not actually
342 // a map. 421 // a map.
343 name = 'dynamic'; 422 name = 'dynamic';
344 comment = 'JSMap of <' + this.generateDartTypeName(indexSig.parameters [0].type, true) + 423 comment = 'JSMap of <' +
345 ',' + this.generateDartTypeName(indexSig.type, true) + '>'; 424 this.generateDartTypeName(indexSig.parameters[0].type, addInsideCo mment(options)) +
425 ',' + this.generateDartTypeName(indexSig.type, addInsideComment(op tions)) + '>';
346 } else { 426 } else {
347 name = 'dynamic'; 427 name = 'dynamic';
348 comment = node.getText(); 428 comment = node.getText();
349 } 429 }
350 break; 430 break;
351 case ts.SyntaxKind.FunctionType: 431 case ts.SyntaxKind.FunctionType:
352 let callSignature = <ts.FunctionOrConstructorTypeNode>node; 432 let callSignature = <ts.FunctionOrConstructorTypeNode>node;
353 let parameters = callSignature.parameters; 433 // TODO(jacobr): instead of removing the expected type of the this param eter, we could add
354 434 // seperate VoidFuncBindThis and FuncBindThis typedefs to package:func/f unc.dart if we
435 // decide indicating the parameter type of the bound this is useful enou gh. As JavaScript
436 // is moving away from binding this
437 let parameters = base.filterThisParameter(callSignature.parameters);
355 // Use a function signature from package:func where possible. 438 // Use a function signature from package:func where possible.
356 let numOptional = numOptionalParameters(parameters); 439 let numOptional = numOptionalParameters(parameters);
357 let isVoid = callSignature.type && callSignature.type.kind === ts.Syntax Kind.VoidKeyword; 440 let isVoid = callSignature.type && callSignature.type.kind === ts.Syntax Kind.VoidKeyword;
358 if (parameters.length <= MAX_DART_FUNC_ACTION_PARAMETERS && 441 if (parameters.length <= MAX_DART_FUNC_ACTION_PARAMETERS &&
359 numOptional <= MAX_DART_FUNC_ACTION_PARAMETERS_OPTIONAL && !hasVarAr gs(parameters)) { 442 numOptional <= MAX_DART_FUNC_ACTION_PARAMETERS_OPTIONAL && !hasVarAr gs(parameters)) {
360 this.emitImport('package:func/func.dart'); 443 this.emitImport('package:func/func.dart');
361 let typeDefName = (isVoid) ? 'VoidFunc' : 'Func'; 444 let typeDefName = (isVoid) ? 'VoidFunc' : 'Func';
362 typeDefName += parameters.length; 445 typeDefName += parameters.length.toString();
363 if (numOptional > 0) { 446 if (numOptional > 0) {
364 typeDefName += 'Opt' + numOptional; 447 typeDefName += 'Opt' + numOptional;
365 } 448 }
366 name = typeDefName; 449 name = typeDefName;
367 let numArgs = parameters.length + (isVoid ? 0 : 1); 450 let numArgs = parameters.length + (isVoid ? 0 : 1);
368 if (numArgs > 0) { 451 if (numArgs > 0) {
369 name += '<'; 452 name += '<';
370 } 453 }
371 let isFirst = true; 454 let isFirst = true;
372 for (let i = 0; i < parameters.length; ++i) { 455 for (let i = 0; i < parameters.length; ++i) {
373 if (isFirst) { 456 if (isFirst) {
374 isFirst = false; 457 isFirst = false;
375 } else { 458 } else {
376 name += ', '; 459 name += ', ';
377 } 460 }
378 name += this.generateDartTypeName(parameters[i].type, insideComment) ; 461 name += this.generateDartTypeName(parameters[i].type, addInsideTypeA rgument(options));
379 } 462 }
380 if (!isVoid) { 463 if (!isVoid) {
381 if (!isFirst) { 464 if (!isFirst) {
382 name += ', '; 465 name += ', ';
383 } 466 }
384 name += this.generateDartTypeName(callSignature.type, insideComment) ; 467 name += this.generateDartTypeName(callSignature.type, addInsideTypeA rgument(options));
385 } 468 }
386 if (numArgs > 0) { 469 if (numArgs > 0) {
387 name += '>'; 470 name += '>';
388 } 471 }
389 } else { 472 } else {
390 name = 'Function'; 473 name = 'Function';
391 if (node.getSourceFile()) { 474 if (node.getSourceFile()) {
392 comment = node.getText(); 475 comment = node.getText();
393 } 476 }
394 } 477 }
395 break; 478 break;
396 case ts.SyntaxKind.ArrayType: 479 case ts.SyntaxKind.ArrayType:
397 name = 'List' + 480 name = 'List' +
398 '<' + this.generateDartTypeName((<ts.ArrayTypeNode>node).elementType , insideComment) + 481 '<' +
482 this.generateDartTypeName(
483 (<ts.ArrayTypeNode>node).elementType, addInsideTypeArgument(opti ons)) +
399 '>'; 484 '>';
400 break; 485 break;
401 case ts.SyntaxKind.NumberKeyword: 486 case ts.SyntaxKind.NumberKeyword:
402 name = 'num'; 487 name = 'num';
403 break; 488 break;
489 case ts.SyntaxKind.StringLiteralType:
490 comment = '\'' + (node as ts.StringLiteralTypeNode).text + '\'';
491 name = 'String';
492 break;
404 case ts.SyntaxKind.StringLiteral: 493 case ts.SyntaxKind.StringLiteral:
405 case ts.SyntaxKind.StringKeyword: 494 case ts.SyntaxKind.StringKeyword:
406 name = 'String'; 495 name = 'String';
407 break; 496 break;
497 case ts.SyntaxKind.NullKeyword:
498 name = 'Null';
499 break;
500 case ts.SyntaxKind.UndefinedKeyword:
501 // TODO(jacobr): unclear if this should be Null or dynamic.
502 name = 'dynamic';
503 break;
408 case ts.SyntaxKind.VoidKeyword: 504 case ts.SyntaxKind.VoidKeyword:
409 name = 'void'; 505 // void cannot be used as a type argument in Dart so we fall back to Obj ect if void is
506 // unfortunately specified as a type argument.
507 name = options.insideTypeArgument ? 'Null' : 'void';
410 break; 508 break;
411 case ts.SyntaxKind.BooleanKeyword: 509 case ts.SyntaxKind.BooleanKeyword:
412 name = 'bool'; 510 name = 'bool';
413 break; 511 break;
414 case ts.SyntaxKind.AnyKeyword: 512 case ts.SyntaxKind.AnyKeyword:
415 name = 'dynamic'; 513 name = 'dynamic';
416 break; 514 break;
515 case ts.SyntaxKind.ParenthesizedType:
516 return this.generateDartTypeName((node as ts.ParenthesizedTypeNode).type , options);
517 case ts.SyntaxKind.ThisType:
518 return this.generateDartName(base.getEnclosingClass(node).name, options) ;
417 default: 519 default:
418 this.reportError(node, 'Unexpected TypeNode kind'); 520 this.reportError(node, 'Unexpected TypeNode kind: ' + node.kind);
419 } 521 }
420 if (name == null) { 522 if (name == null) {
421 name = 'XXX NULLNAME'; 523 name = 'ERROR_NULL_NAME';
422 } 524 }
423 525
424 name = name.trim(); 526 name = name.trim();
425 return base.formatType(name, comment, insideComment); 527 return base.formatType(name, comment, options);
426 } 528 }
427 529
428 visitTypeName(typeName: ts.EntityName) { 530 visitTypeName(typeName: ts.EntityName) {
429 if (typeName.kind !== ts.SyntaxKind.Identifier) { 531 if (typeName.kind !== ts.SyntaxKind.Identifier) {
430 this.visit(typeName); 532 this.visit(typeName);
431 return; 533 return;
432 } 534 }
433 let ident = base.ident(typeName); 535 let ident = base.ident(typeName);
434 if (this.isGenericMethodTypeParameterName(typeName)) { 536 if (this.isGenericMethodTypeParameterName(typeName)) {
435 // DDC generic methods hack - all names that are type parameters to generi c methods have to be 537 // DDC generic methods hack - all names that are type parameters to generi c methods have to be
436 // emitted in comments. 538 // emitted in comments.
437 this.emitType('dynamic', ident); 539 this.emitType('dynamic', ident);
438 return; 540 return;
439 } 541 }
440 542
441 let custom = this.lookupCustomDartTypeName(<ts.Identifier>typeName, this.ins ideCodeComment); 543 let custom = this.lookupCustomDartTypeName(
544 <ts.Identifier>typeName,
545 {insideComment: this.insideCodeComment, insideTypeArgument: this.insideT ypeArgument});
442 if (custom) { 546 if (custom) {
443 if (custom.comment) { 547 if (custom.comment) {
444 this.emitType(custom.name, custom.comment); 548 this.emitType(custom.name, custom.comment);
445 } else { 549 } else {
446 this.emit(custom.name); 550 this.emit(custom.name);
447 } 551 }
448 } else { 552 } else {
449 this.visit(typeName); 553 this.visit(typeName);
450 } 554 }
451 } 555 }
452 556
453 getSymbolDeclaration(symbol: ts.Symbol, n?: ts.Node): ts.Declaration { 557 getSymbolDeclaration(symbol: ts.Symbol, n?: ts.Node): ts.Declaration {
454 if (!symbol) return null; 558 if (!symbol) return null;
455 let decl = symbol.valueDeclaration; 559 let decl = symbol.valueDeclaration;
456 if (!decl) { 560 if (!decl) {
457 // In the case of a pure declaration with no assignment, there is no value declared. 561 // In the case of a pure declaration with no assignment, there is no value declared.
458 // Just grab the first declaration, hoping it is declared once. 562 // Just grab the first declaration, hoping it is declared once.
459 if (!symbol.declarations || symbol.declarations.length === 0) { 563 if (!symbol.declarations || symbol.declarations.length === 0) {
460 this.reportError(n, 'no declarations for symbol ' + symbol.name); 564 this.reportError(n, 'no declarations for symbol ' + symbol.name);
461 return; 565 return;
462 } 566 }
463 decl = symbol.declarations[0]; 567 decl = symbol.declarations[0];
464 } 568 }
465 return decl; 569 return decl;
466 } 570 }
467 571
468 generateDartName(identifier: ts.EntityName, insideComment: boolean): string { 572 generateDartName(identifier: ts.EntityName, options: TypeDisplayOptions): stri ng {
469 let ret = this.lookupCustomDartTypeName(identifier, insideComment); 573 let ret = this.lookupCustomDartTypeName(identifier, options);
470 if (ret) return base.formatType(ret.name, ret.comment, insideComment); 574
471 // TODO(jacobr): handle library import prefixes better. This generally works 575 if (ret) {
472 // but is somewhat fragile. 576 return base.formatType(ret.name, ret.comment, options);
473 return base.ident(identifier); 577 }
578 // TODO(jacobr): handle library import prefixes more robustly. This generall y works
579 // but is fragile.
580 return this.maybeAddTypeArguments(base.ident(identifier), options);
474 } 581 }
475 582
476 /** 583 /**
477 * Returns null if declaration cannot be found or is not valid in Dart. 584 * Returns null if declaration cannot be found or is not valid in Dart.
478 */ 585 */
479 getDeclaration(identifier: ts.EntityName): ts.Declaration { 586 getDeclaration(identifier: ts.EntityName): ts.Declaration {
480 let symbol: ts.Symbol; 587 let symbol: ts.Symbol;
481 if (!this.tc) return null; 588 if (!this.tc) return null;
482 589
483 symbol = this.tc.getSymbolAtLocation(identifier); 590 symbol = this.tc.getSymbolAtLocation(identifier);
484 let declaration = this.getSymbolDeclaration(symbol, identifier); 591 let declaration = this.getSymbolDeclaration(symbol, identifier);
485 if (symbol && symbol.flags & ts.SymbolFlags.TypeParameter) { 592 if (symbol && symbol.flags & ts.SymbolFlags.TypeParameter) {
486 let kind = declaration.parent.kind; 593 let kind = declaration.parent.kind;
487 // Only kinds of TypeParameters supported by Dart. 594 // Only kinds of TypeParameters supported by Dart.
488 if (kind !== ts.SyntaxKind.ClassDeclaration && kind !== ts.SyntaxKind.Inte rfaceDeclaration) { 595 if (kind !== ts.SyntaxKind.ClassDeclaration && kind !== ts.SyntaxKind.Inte rfaceDeclaration) {
489 return null; 596 return null;
490 } 597 }
491 } 598 }
492 return declaration; 599 return declaration;
493 } 600 }
494 601
602 maybeAddTypeArguments(name: string, options: TypeDisplayOptions): string {
603 if (options.typeArguments) {
604 name +=
605 '<' + this.generateTypeList(options.typeArguments, setTypeArguments(op tions, null)) + '>';
606 }
607 return name;
608 }
609
495 /** 610 /**
496 * Returns a custom Dart type name or null if the type isn't a custom Dart 611 * Returns a custom Dart type name or null if the type isn't a custom Dart
497 * type. 612 * type.
498 */ 613 */
499 lookupCustomDartTypeName(identifier: ts.EntityName, insideComment: boolean): 614 lookupCustomDartTypeName(identifier: ts.EntityName, options?: TypeDisplayOptio ns):
500 {name?: string, comment?: string, keep?: boolean} { 615 {name?: string, comment?: string, keep?: boolean} {
616 if (!options) {
617 options = {
618 insideComment: this.insideCodeComment,
619 insideTypeArgument: this.insideTypeArgument
620 };
621 }
501 let ident = base.ident(identifier); 622 let ident = base.ident(identifier);
502 let symbol: ts.Symbol; 623 let symbol: ts.Symbol = this.tc.getSymbolAtLocation(identifier);
503 if (!this.tc) return null;
504
505 symbol = this.tc.getSymbolAtLocation(identifier);
506 let declaration = this.getSymbolDeclaration(symbol, identifier); 624 let declaration = this.getSymbolDeclaration(symbol, identifier);
507 if (symbol && symbol.flags & ts.SymbolFlags.TypeParameter) { 625 if (symbol && symbol.flags & ts.SymbolFlags.TypeParameter) {
508 let kind = declaration.parent.kind; 626 let kind = declaration.parent.kind;
627 if (options.resolvedTypeArguments &&
628 Object.hasOwnProperty.call(options.resolvedTypeArguments, ident)) {
629 return {
630 name: this.generateDartTypeName(
631 options.resolvedTypeArguments[ident], removeResolvedTypeArguments( options))
632 };
633 }
509 // Only kinds of TypeParameters supported by Dart. 634 // Only kinds of TypeParameters supported by Dart.
510 if (kind !== ts.SyntaxKind.ClassDeclaration && kind !== ts.SyntaxKind.Inte rfaceDeclaration) { 635 if (kind !== ts.SyntaxKind.ClassDeclaration && kind !== ts.SyntaxKind.Inte rfaceDeclaration &&
636 kind !== ts.SyntaxKind.TypeAliasDeclaration) {
511 return {name: 'dynamic', comment: ident}; 637 return {name: 'dynamic', comment: ident};
512 } 638 }
513 } 639 }
514 640
515 if (this.candidateTypes.hasOwnProperty(ident)) { 641 if (this.candidateTypes.hasOwnProperty(ident)) {
516 if (!symbol) { 642 if (!symbol) {
517 return null; 643 return null;
518 } 644 }
519 645
520 let fileAndName = this.getFileAndName(identifier, symbol); 646 let fileAndName = this.getFileAndName(identifier, symbol);
521 647
522 if (fileAndName) { 648 if (fileAndName) {
523 let fileSubs = TS_TO_DART_TYPENAMES[fileAndName.fileName]; 649 let fileSubs = TS_TO_DART_TYPENAMES[fileAndName.fileName];
524 if (fileSubs) { 650 if (fileSubs) {
525 let dartBrowserType = DART_LIBRARIES_FOR_BROWSER_TYPES.hasOwnProperty( fileAndName.qname); 651 let dartBrowserType = DART_LIBRARIES_FOR_BROWSER_TYPES.hasOwnProperty( fileAndName.qname);
526 if (dartBrowserType) { 652 if (dartBrowserType) {
527 this.emitImport(DART_LIBRARIES_FOR_BROWSER_TYPES[fileAndName.qname]) ; 653 this.emitImport(DART_LIBRARIES_FOR_BROWSER_TYPES[fileAndName.qname]) ;
528 } 654 }
529 if (fileSubs.hasOwnProperty(fileAndName.qname)) { 655 if (fileSubs.hasOwnProperty(fileAndName.qname)) {
530 return {name: fileSubs[fileAndName.qname]}; 656 return {name: this.maybeAddTypeArguments(fileSubs[fileAndName.qname] , options)};
531 } 657 }
532 if (dartBrowserType) { 658 if (dartBrowserType) {
533 // Not a rename but has a dart core libraries definition. 659 // Not a rename but has a dart core libraries definition.
534 return {name: fileAndName.qname}; 660 return {name: this.maybeAddTypeArguments(fileAndName.qname, options) };
535 } 661 }
536 } 662 }
537 } 663 }
538 } 664 }
539 if (symbol) { 665 if (symbol) {
666 this.emitImportForSourceFile(declaration.getSourceFile(), identifier.getSo urceFile());
540 if (symbol.flags & ts.SymbolFlags.Enum) { 667 if (symbol.flags & ts.SymbolFlags.Enum) {
541 // We can't treat JavaScript enums as Dart enums in this case. 668 // We can't treat JavaScript enums as Dart enums in this case.
542 return {name: 'num', comment: ident}; 669 return {name: 'num', comment: 'enum ' + ident};
543 } 670 }
544 // TODO(jacobr): we could choose to only support type alais declarations 671 // TODO(jacobr): we could choose to only support type alais declarations
545 // for JS interop but it seems handling type alaises is generally helpful 672 // for JS interop but it seems handling type alaises is generally helpful
546 // without much risk of generating confusing Dart code. 673 // without much risk of generating confusing Dart code.
547 if (declaration.kind === ts.SyntaxKind.TypeAliasDeclaration) { 674 if (declaration.kind === ts.SyntaxKind.TypeAliasDeclaration) {
548 let alias = <ts.TypeAliasDeclaration>declaration; 675 let alias = <ts.TypeAliasDeclaration>declaration;
549 if (alias.typeParameters) { 676 if (base.supportedAliasType(alias)) {
550 // We can handle this case but currently do not. 677 return {
551 this.reportError(declaration, 'Type parameters for type alaises are no t supported'); 678 name: this.maybeAddTypeArguments(
679 this.nameRewriter.lookupName(<base.NamedDeclaration>declaration, identifier),
680 options),
681 keep: true
682 };
552 } 683 }
553 return {name: this.generateDartTypeName(alias.type, insideComment)}; 684 // Type alias we cannot support in Dart.
685 // Substitute the alias type and parameters directly in the destination.
686 return {
687 name: this.generateDartTypeName(
688 alias.type, resolveTypeArguments(options, alias.typeParameters))
689 };
554 } 690 }
555 691
556 let kind = declaration.kind; 692 let kind = declaration.kind;
557 if (kind === ts.SyntaxKind.ClassDeclaration || kind === ts.SyntaxKind.Inte rfaceDeclaration || 693 if (kind === ts.SyntaxKind.ClassDeclaration || kind === ts.SyntaxKind.Inte rfaceDeclaration ||
558 kind === ts.SyntaxKind.VariableDeclaration || 694 kind === ts.SyntaxKind.VariableDeclaration ||
559 kind === ts.SyntaxKind.PropertyDeclaration || 695 kind === ts.SyntaxKind.PropertyDeclaration ||
560 kind === ts.SyntaxKind.FunctionDeclaration) { 696 kind === ts.SyntaxKind.FunctionDeclaration) {
561 let name = this.nameRewriter.lookupName(<base.NamedDeclaration>declarati on, identifier); 697 let name = this.nameRewriter.lookupName(<base.NamedDeclaration>declarati on, identifier);
562 if (kind === ts.SyntaxKind.InterfaceDeclaration && 698 if (kind === ts.SyntaxKind.InterfaceDeclaration &&
563 base.isFunctionTypedefLikeInterface(<ts.InterfaceDeclaration>declara tion) && 699 base.isFunctionTypedefLikeInterface(<ts.InterfaceDeclaration>declara tion) &&
564 base.getAncestor(identifier, ts.SyntaxKind.HeritageClause)) { 700 base.getAncestor(identifier, ts.SyntaxKind.HeritageClause)) {
565 // TODO(jacobr): we need to specify a specific call method for this 701 // TODO(jacobr): we need to specify a specific call method for this
566 // case if we want to get the most from Dart type checking. 702 // case if we want to get the most from Dart type checking.
567 return {name: 'Function', comment: name}; 703 return {name: 'Function', comment: name};
568 } 704 }
569 return {name: name, keep: true}; 705 return {name: this.maybeAddTypeArguments(name, options), keep: true};
570 } 706 }
571 } 707 }
572 return null; 708 return null;
573 } 709 }
574 710
575 // TODO(jacobr): performance of this method could easily be optimized. 711 // TODO(jacobr): performance of this method could easily be optimized.
576 /** 712 /**
577 * This method works around the lack of Dart support for union types 713 * This method works around the lack of Dart support for union types
578 * generating a valid Dart type that satisfies all the types passed in. 714 * generating a valid Dart type that satisfies all the types passed in.
579 */ 715 */
580 toSimpleDartType(types: Array<ts.TypeNode>) { 716 toSimpleDartType(types: Array<ts.TypeNode>): ts.TypeNode {
581 // We use MergeType to ensure that we have already deduped types that are 717 // We use MergeType to ensure that we have already deduped types that are
582 // equivalent even if they aren't obviously identical. 718 // equivalent even if they aren't obviously identical.
583 // MergedType will also follow typed aliases, etc which allows us to avoid 719 // MergedType will also follow typed aliases, etc which allows us to avoid
584 // including that logic here as well. 720 // including that logic here as well.
585 let mergedType = new MergedType(this); 721 let mergedType = new MergedType(this);
586 types.forEach((type) => { mergedType.merge(type); }); 722 types.forEach((type) => { mergedType.merge(type); });
587 let merged = mergedType.toTypeNode(); 723 let merged = mergedType.toTypeNode();
724
725 if (merged == null) return null;
726
588 if (merged.kind === ts.SyntaxKind.UnionType) { 727 if (merged.kind === ts.SyntaxKind.UnionType) {
589 // For union types find a Dart type that satisfies all the types. 728 // For union types find a Dart type that satisfies all the types.
590 types = (<ts.UnionTypeNode>merged).types; 729 types = (<ts.UnionTypeNode>merged).types;
591 /** 730 /**
592 * Generate a common base type for an array of types. 731 * Generate a common base type for an array of types.
593 * The implemented is currently incomplete often returning null when there 732 * The implemented is currently incomplete often returning null when there
594 * might really be a valid common base type. 733 * might really be a valid common base type.
595 */ 734 */
596 let common: ts.TypeNode = types[0]; 735 let common: ts.TypeNode = types[0];
597 for (let i = 1; i < types.length && common != null; ++i) { 736 for (let i = 1; i < types.length && common != null; ++i) {
598 let type = types[i]; 737 let type = types[i];
599 if (common !== type) { 738 common = this.findCommonType(type, common);
600 if (base.isCallableType(common, this.tc) && base.isCallableType(type, this.tc)) {
601 // Fall back to a generic Function type if both types are Function.
602 let fn = <ts.FunctionOrConstructorTypeNode>ts.createNode(ts.SyntaxKi nd.FunctionType);
603 fn.parameters = <ts.NodeArray<ts.ParameterDeclaration>>[];
604 let parameter = <ts.ParameterDeclaration>ts.createNode(ts.SyntaxKind .Parameter);
605 parameter.dotDotDotToken = ts.createNode(ts.SyntaxKind.DotDotDotToke n);
606 let name = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier);
607 name.text = 'args';
608 fn.parameters.push(parameter);
609 common = fn;
610 } else {
611 switch (type.kind) {
612 case ts.SyntaxKind.ArrayType:
613 if (common.kind !== ts.SyntaxKind.ArrayType) {
614 return null;
615 }
616 let array = <ts.ArrayTypeNode>ts.createNode(ts.SyntaxKind.ArrayT ype);
617 array.elementType = this.toSimpleDartType([
618 (common as ts.ArrayTypeNode).elementType, (type as ts.ArrayTyp eNode).elementType
619 ]);
620 common = array;
621 break;
622 // case ts.SyntaxKind
623 case ts.SyntaxKind.TypeReference:
624 if (common.kind !== ts.SyntaxKind.TypeReference) {
625 return null;
626 }
627 common = this.commonSupertype(common, type);
628 break;
629
630 default:
631 return null;
632 }
633 }
634 }
635 } 739 }
636 return common; 740 return common;
637 } 741 }
638 return merged; 742 return merged;
639 } 743 }
640 744
745 findCommonType(type: ts.TypeNode, common: ts.TypeNode): ts.TypeNode {
746 if (common === type) return common;
747
748 // If both types generate the exact same Dart type name without comments the n
749 // there is no need to do anything. The types
750 if (this.generateDartTypeName(common, {hideComment: true}) ===
751 this.generateDartTypeName(type, {hideComment: true})) {
752 return common;
753 }
754
755
756 if (type.kind === ts.SyntaxKind.ArrayType) {
757 if (common.kind !== ts.SyntaxKind.ArrayType) {
758 return null;
759 }
760 let array = <ts.ArrayTypeNode>ts.createNode(ts.SyntaxKind.ArrayType);
761 array.elementType = this.toSimpleDartType(
762 [(common as ts.ArrayTypeNode).elementType, (type as ts.ArrayTypeNode). elementType]);
763 return array;
764 }
765 if (type.kind === ts.SyntaxKind.TypeReference && common.kind === ts.SyntaxKi nd.TypeReference) {
766 let candidate = this.commonSupertype(common, type);
767 if (candidate !== null) {
768 return candidate;
769 }
770 }
771
772 if (base.isCallableType(common, this.tc) && base.isCallableType(type, this.t c)) {
773 // Fall back to a generic Function type if both types are Function.
774 // TODO(jacobr): this is a problematic fallback.
775 let fn = <ts.FunctionOrConstructorTypeNode>ts.createNode(ts.SyntaxKind.Fun ctionType);
776 fn.parameters = <ts.NodeArray<ts.ParameterDeclaration>>[];
777 let parameter = <ts.ParameterDeclaration>ts.createNode(ts.SyntaxKind.Param eter);
778 parameter.dotDotDotToken = ts.createNode(ts.SyntaxKind.DotDotDotToken);
779 let name = <ts.Identifier>ts.createNode(ts.SyntaxKind.Identifier);
780 name.text = 'args';
781 fn.parameters.push(parameter);
782 return fn;
783 }
784 // No common type found.
785 return null;
786 }
787
641 toTypeNode(type: ts.Type): ts.TypeNode { 788 toTypeNode(type: ts.Type): ts.TypeNode {
642 if (!type) return null; 789 if (!type) return null;
643 let symbol = type.getSymbol(); 790 let symbol = type.getSymbol();
644 if (!symbol) return null; 791 if (!symbol) return null;
645 792
646 let referenceType = <ts.TypeReferenceNode>ts.createNode(ts.SyntaxKind.TypeRe ference); 793 let referenceType = <ts.TypeReferenceNode>ts.createNode(ts.SyntaxKind.TypeRe ference);
647 // TODO(jacobr): property need to prefix the name better. 794 // TODO(jacobr): property need to prefix the name better.
648 referenceType.typeName = this.createEntityName(symbol); 795 referenceType.typeName = this.createEntityName(symbol);
649 referenceType.typeName.parent = referenceType; 796 referenceType.typeName.parent = referenceType;
650 return referenceType; 797 return referenceType;
(...skipping 27 matching lines...) Expand all
678 if (!(source.flags & ts.TypeFlags.Interface)) return false; 825 if (!(source.flags & ts.TypeFlags.Interface)) return false;
679 let baseTypes = this.safeGetBaseTypes(source as ts.InterfaceType); 826 let baseTypes = this.safeGetBaseTypes(source as ts.InterfaceType);
680 for (let i = 0; i < baseTypes.length; ++i) { 827 for (let i = 0; i < baseTypes.length; ++i) {
681 if (baseTypes[i] === target) return true; 828 if (baseTypes[i] === target) return true;
682 } 829 }
683 return false; 830 return false;
684 } 831 }
685 832
686 commonSupertype(nodeA: ts.TypeNode, nodeB: ts.TypeNode): ts.TypeNode { 833 commonSupertype(nodeA: ts.TypeNode, nodeB: ts.TypeNode): ts.TypeNode {
687 if (nodeA == null || nodeB == null) return null; 834 if (nodeA == null || nodeB == null) return null;
835 if (nodeA.kind === ts.SyntaxKind.TypeReference && nodeB.kind === ts.SyntaxKi nd.TypeReference) {
836 // Handle the trivial case where the types are identical except for type a rguments.
837 // We could do a better job and actually attempt to merge type arguments.
838 let refA = nodeA as ts.TypeReferenceNode;
839 let refB = nodeB as ts.TypeReferenceNode;
840 if (base.ident(refA.typeName) === base.ident(refB.typeName)) {
841 let merge = <ts.TypeReferenceNode>ts.createNode(ts.SyntaxKind.TypeRefere nce);
842 merge.typeName = refA.typeName;
843 return merge;
844 }
845 }
688 return this.toTypeNode(this.getCommonSupertype( 846 return this.toTypeNode(this.getCommonSupertype(
689 this.tc.getTypeAtLocation(nodeA), this.tc.getTypeAtLocation(nodeB))); 847 this.tc.getTypeAtLocation(nodeA), this.tc.getTypeAtLocation(nodeB)));
690 } 848 }
691 849
692 getCommonSupertype(a: ts.Type, b: ts.Type): ts.Type { 850 getCommonSupertype(a: ts.Type, b: ts.Type): ts.Type {
693 if (a === b) return a;
694 // This logic was probably a mistake. It adds a lot of complexity and we can 851 // This logic was probably a mistake. It adds a lot of complexity and we can
695 // do better performing these calculations in the Dart analyzer based 852 // do better performing these calculations in the Dart analyzer based
696 // directly on the union types specified in comments. 853 // directly on the union types specified in comments.
697 return null; 854 return null;
698 /* 855 /*
699 if (!(a.flags & ts.TypeFlags.Interface) || !(b.flags & ts.TypeFlags.Inte rface)) { 856 if (!(a.flags & ts.TypeFlags.Interface) || !(b.flags & ts.TypeFlags.Inte rface)) {
700 return null; 857 return null;
701 } 858 }
702 859
703 let bestCommonSuperType: ts.Type = null; 860 let bestCommonSuperType: ts.Type = null;
(...skipping 26 matching lines...) Expand all
730 let qname = this.tc.getFullyQualifiedName(symbol); 887 let qname = this.tc.getFullyQualifiedName(symbol);
731 // Some Qualified Names include their file name. Might be a bug in TypeScrip t, 888 // Some Qualified Names include their file name. Might be a bug in TypeScrip t,
732 // for the time being just special case. 889 // for the time being just special case.
733 if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.Symb olFlags.Variable)) { 890 if (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Function | ts.Symb olFlags.Variable)) {
734 qname = symbol.getName(); 891 qname = symbol.getName();
735 } 892 }
736 if (FACADE_DEBUG) console.error('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname); 893 if (FACADE_DEBUG) console.error('fn:', fileName, 'cfn:', canonicalFileName, 'qn:', qname);
737 return {fileName: canonicalFileName, qname}; 894 return {fileName: canonicalFileName, qname};
738 } 895 }
739 } 896 }
OLDNEW
« no previous file with comments | « lib/declaration.ts ('k') | lib/main.ts » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698