fix(compiler): generate the correct imports for summary type-check
Summaries should be ignored when importing the types used in a type-check block.
This commit is contained in:
parent
d213a20dfc
commit
d91ff17adc
|
@ -12,6 +12,7 @@ import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import * as ng from '../index';
|
import * as ng from '../index';
|
||||||
|
|
||||||
|
// TEST_TMPDIR is set by bazel.
|
||||||
const tmpdir = process.env.TEST_TMPDIR || os.tmpdir();
|
const tmpdir = process.env.TEST_TMPDIR || os.tmpdir();
|
||||||
|
|
||||||
function getNgRootDir() {
|
function getNgRootDir() {
|
||||||
|
@ -21,7 +22,6 @@ function getNgRootDir() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writeTempFile(name: string, contents: string): string {
|
export function writeTempFile(name: string, contents: string): string {
|
||||||
// TEST_TMPDIR is set by bazel.
|
|
||||||
const id = (Math.random() * 1000000).toFixed(0);
|
const id = (Math.random() * 1000000).toFixed(0);
|
||||||
const fn = path.join(tmpdir, `tmp.${id}.${name}`);
|
const fn = path.join(tmpdir, `tmp.${id}.${name}`);
|
||||||
fs.writeFileSync(fn, contents);
|
fs.writeFileSync(fn, contents);
|
||||||
|
@ -29,8 +29,12 @@ export function writeTempFile(name: string, contents: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeTempDir(): string {
|
export function makeTempDir(): string {
|
||||||
const id = (Math.random() * 1000000).toFixed(0);
|
let dir: string;
|
||||||
const dir = path.join(tmpdir, `tmp.${id}`);
|
while (true) {
|
||||||
|
const id = (Math.random() * 1000000).toFixed(0);
|
||||||
|
dir = path.join(tmpdir, `tmp.${id}`);
|
||||||
|
if (!fs.existsSync(dir)) break;
|
||||||
|
}
|
||||||
fs.mkdirSync(dir);
|
fs.mkdirSync(dir);
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,15 +218,14 @@ export class AotCompiler {
|
||||||
|
|
||||||
const externalReferenceVars = new Map<any, string>();
|
const externalReferenceVars = new Map<any, string>();
|
||||||
externalReferences.forEach((ref, typeIndex) => {
|
externalReferences.forEach((ref, typeIndex) => {
|
||||||
if (this._host.isSourceFile(ref.filePath)) {
|
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
|
||||||
externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
externalReferenceVars.forEach((varName, reference) => {
|
externalReferenceVars.forEach((varName, reference) => {
|
||||||
outputCtx.statements.push(
|
outputCtx.statements.push(
|
||||||
o.variable(varName)
|
o.variable(varName)
|
||||||
.set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE))
|
.set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE))
|
||||||
.toDeclStmt(o.expressionType(outputCtx.importExpr(reference))));
|
.toDeclStmt(o.expressionType(outputCtx.importExpr(
|
||||||
|
reference, /* typeParams */ null, /* useSummaries */ false))));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (emitFlags & StubEmitFlags.TypeCheck) {
|
if (emitFlags & StubEmitFlags.TypeCheck) {
|
||||||
|
@ -515,35 +514,38 @@ export class AotCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createOutputContext(genFilePath: string): OutputContext {
|
private _createOutputContext(genFilePath: string): OutputContext {
|
||||||
const importExpr = (symbol: StaticSymbol, typeParams: o.Type[] | null = null) => {
|
const importExpr =
|
||||||
if (!(symbol instanceof StaticSymbol)) {
|
(symbol: StaticSymbol, typeParams: o.Type[] | null = null,
|
||||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
useSummaries: boolean = true) => {
|
||||||
}
|
if (!(symbol instanceof StaticSymbol)) {
|
||||||
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
|
throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`);
|
||||||
const {filePath, name, members} = this._symbolResolver.getImportAs(symbol) || symbol;
|
}
|
||||||
const importModule = this._fileNameToModuleName(filePath, genFilePath);
|
const arity = this._symbolResolver.getTypeArity(symbol) || 0;
|
||||||
|
const {filePath, name, members} =
|
||||||
|
this._symbolResolver.getImportAs(symbol, useSummaries) || symbol;
|
||||||
|
const importModule = this._fileNameToModuleName(filePath, genFilePath);
|
||||||
|
|
||||||
// It should be good enough to compare filePath to genFilePath and if they are equal
|
// It should be good enough to compare filePath to genFilePath and if they are equal
|
||||||
// there is a self reference. However, ngfactory files generate to .ts but their
|
// there is a self reference. However, ngfactory files generate to .ts but their
|
||||||
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
|
// symbols have .d.ts so a simple compare is insufficient. They should be canonical
|
||||||
// and is tracked by #17705.
|
// and is tracked by #17705.
|
||||||
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
|
const selfReference = this._fileNameToModuleName(genFilePath, genFilePath);
|
||||||
const moduleName = importModule === selfReference ? null : importModule;
|
const moduleName = importModule === selfReference ? null : importModule;
|
||||||
|
|
||||||
// If we are in a type expression that refers to a generic type then supply
|
// If we are in a type expression that refers to a generic type then supply
|
||||||
// the required type parameters. If there were not enough type parameters
|
// the required type parameters. If there were not enough type parameters
|
||||||
// supplied, supply any as the type. Outside a type expression the reference
|
// supplied, supply any as the type. Outside a type expression the reference
|
||||||
// should not supply type parameters and be treated as a simple value reference
|
// should not supply type parameters and be treated as a simple value reference
|
||||||
// to the constructor function itself.
|
// to the constructor function itself.
|
||||||
const suppliedTypeParams = typeParams || [];
|
const suppliedTypeParams = typeParams || [];
|
||||||
const missingTypeParamsCount = arity - suppliedTypeParams.length;
|
const missingTypeParamsCount = arity - suppliedTypeParams.length;
|
||||||
const allTypeParams =
|
const allTypeParams =
|
||||||
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
|
suppliedTypeParams.concat(new Array(missingTypeParamsCount).fill(o.DYNAMIC_TYPE));
|
||||||
return members.reduce(
|
return members.reduce(
|
||||||
(expr, memberName) => expr.prop(memberName),
|
(expr, memberName) => expr.prop(memberName),
|
||||||
<o.Expression>o.importExpr(
|
<o.Expression>o.importExpr(
|
||||||
new o.ExternalReference(moduleName, name, null), allTypeParams));
|
new o.ExternalReference(moduleName, name, null), allTypeParams));
|
||||||
};
|
};
|
||||||
|
|
||||||
return {statements: [], genFilePath, importExpr};
|
return {statements: [], genFilePath, importExpr};
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,10 +98,10 @@ export class StaticSymbolResolver {
|
||||||
*
|
*
|
||||||
* @param staticSymbol the symbol for which to generate a import symbol
|
* @param staticSymbol the symbol for which to generate a import symbol
|
||||||
*/
|
*/
|
||||||
getImportAs(staticSymbol: StaticSymbol): StaticSymbol|null {
|
getImportAs(staticSymbol: StaticSymbol, useSummaries: boolean = true): StaticSymbol|null {
|
||||||
if (staticSymbol.members.length) {
|
if (staticSymbol.members.length) {
|
||||||
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
const baseSymbol = this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name);
|
||||||
const baseImportAs = this.getImportAs(baseSymbol);
|
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
||||||
return baseImportAs ?
|
return baseImportAs ?
|
||||||
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
|
this.getStaticSymbol(baseImportAs.filePath, baseImportAs.name, staticSymbol.members) :
|
||||||
null;
|
null;
|
||||||
|
@ -111,14 +111,14 @@ export class StaticSymbolResolver {
|
||||||
const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
|
const summarizedName = stripSummaryForJitNameSuffix(staticSymbol.name);
|
||||||
const baseSymbol =
|
const baseSymbol =
|
||||||
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members);
|
||||||
const baseImportAs = this.getImportAs(baseSymbol);
|
const baseImportAs = this.getImportAs(baseSymbol, useSummaries);
|
||||||
return baseImportAs ?
|
return baseImportAs ?
|
||||||
this.getStaticSymbol(
|
this.getStaticSymbol(
|
||||||
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
|
summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name),
|
||||||
baseSymbol.members) :
|
baseSymbol.members) :
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
let result = this.summaryResolver.getImportAs(staticSymbol);
|
let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null;
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = this.importAs.get(staticSymbol) !;
|
result = this.importAs.get(staticSymbol) !;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ export function utf8Encode(str: string): string {
|
||||||
export interface OutputContext {
|
export interface OutputContext {
|
||||||
genFilePath: string;
|
genFilePath: string;
|
||||||
statements: o.Statement[];
|
statements: o.Statement[];
|
||||||
importExpr(reference: any, typeParams?: o.Type[]|null): o.Expression;
|
importExpr(reference: any, typeParams?: o.Type[]|null, useSummaries?: boolean): o.Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stringify(token: any): string {
|
export function stringify(token: any): string {
|
||||||
|
|
|
@ -196,6 +196,25 @@ describe('StaticSymbolResolver', () => {
|
||||||
.toBe(symbolCache.get('/test3.d.ts', 'b'));
|
.toBe(symbolCache.get('/test3.d.ts', 'b'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should ignore summaries for inputAs if requested', () => {
|
||||||
|
init(
|
||||||
|
{
|
||||||
|
'/test.ts': `
|
||||||
|
export {a} from './test2';
|
||||||
|
`
|
||||||
|
},
|
||||||
|
[], [{
|
||||||
|
symbol: symbolCache.get('/test2.d.ts', 'a'),
|
||||||
|
importAs: symbolCache.get('/test3.d.ts', 'b')
|
||||||
|
}]);
|
||||||
|
|
||||||
|
symbolResolver.getSymbolsOf('/test.ts');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a'), /* useSummaries */ false))
|
||||||
|
.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it('should calculate importAs for symbols with members based on importAs for symbols without',
|
it('should calculate importAs for symbols with members based on importAs for symbols without',
|
||||||
() => {
|
() => {
|
||||||
init(
|
init(
|
||||||
|
|
Loading…
Reference in New Issue