mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-20 19:45:07 -06:00
Improve diagnostics deduplication (#58220)
This commit is contained in:
parent
1db1376d8a
commit
ebcb09d71a
@ -808,7 +808,13 @@ export function createSortedArray<T>(): SortedArray<T> {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Comparer<T>, allowDuplicates?: boolean): boolean {
|
||||
export function insertSorted<T>(
|
||||
array: SortedArray<T>,
|
||||
insert: T,
|
||||
compare: Comparer<T>,
|
||||
equalityComparer?: EqualityComparer<T>,
|
||||
allowDuplicates?: boolean,
|
||||
): boolean {
|
||||
if (array.length === 0) {
|
||||
array.push(insert);
|
||||
return true;
|
||||
@ -816,6 +822,16 @@ export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Compa
|
||||
|
||||
const insertIndex = binarySearch(array, insert, identity, compare);
|
||||
if (insertIndex < 0) {
|
||||
if (equalityComparer && !allowDuplicates) {
|
||||
const idx = ~insertIndex;
|
||||
if (idx > 0 && equalityComparer(insert, array[idx - 1])) {
|
||||
return false;
|
||||
}
|
||||
if (idx < array.length && equalityComparer(insert, array[idx])) {
|
||||
array.splice(idx, 1, insert);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
array.splice(~insertIndex, 0, insert);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -5864,6 +5864,9 @@ export function createDiagnosticCollection(): DiagnosticCollection {
|
||||
if (result >= 0) {
|
||||
return diagnostics[result];
|
||||
}
|
||||
if (~result > 0 && diagnosticsEqualityComparer(diagnostic, diagnostics[~result - 1])) {
|
||||
return diagnostics[~result - 1];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -5887,7 +5890,7 @@ export function createDiagnosticCollection(): DiagnosticCollection {
|
||||
diagnostics = nonFileDiagnostics;
|
||||
}
|
||||
|
||||
insertSorted(diagnostics, diagnostic, compareDiagnosticsSkipRelatedInformation);
|
||||
insertSorted(diagnostics, diagnostic, compareDiagnosticsSkipRelatedInformation, diagnosticsEqualityComparer);
|
||||
}
|
||||
|
||||
function getGlobalDiagnostics(): Diagnostic[] {
|
||||
@ -8545,12 +8548,14 @@ export function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Dia
|
||||
Comparison.EqualTo;
|
||||
}
|
||||
|
||||
// A diagnostic with more elaboration should be considered *less than* a diagnostic
|
||||
// with less elaboration that is otherwise similar.
|
||||
function compareRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison {
|
||||
if (!d1.relatedInformation && !d2.relatedInformation) {
|
||||
return Comparison.EqualTo;
|
||||
}
|
||||
if (d1.relatedInformation && d2.relatedInformation) {
|
||||
return compareValues(d1.relatedInformation.length, d2.relatedInformation.length) || forEach(d1.relatedInformation, (d1i, index) => {
|
||||
return compareValues(d2.relatedInformation.length, d1.relatedInformation.length) || forEach(d1.relatedInformation, (d1i, index) => {
|
||||
const d2i = d2.relatedInformation![index];
|
||||
return compareDiagnostics(d1i, d2i); // EqualTo is 0, so falsy, and will cause the next item to be compared
|
||||
}) || Comparison.EqualTo;
|
||||
@ -8558,45 +8563,115 @@ function compareRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison {
|
||||
return d1.relatedInformation ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
}
|
||||
|
||||
function compareMessageText(t1: string | DiagnosticMessageChain, t2: string | DiagnosticMessageChain): Comparison {
|
||||
// An diagnostic message with more elaboration should be considered *less than* a diagnostic message
|
||||
// with less elaboration that is otherwise similar.
|
||||
function compareMessageText(
|
||||
t1: string | Pick<DiagnosticMessageChain, "messageText" | "next">,
|
||||
t2: string | Pick<DiagnosticMessageChain, "messageText" | "next">,
|
||||
): Comparison {
|
||||
if (typeof t1 === "string" && typeof t2 === "string") {
|
||||
return compareStringsCaseSensitive(t1, t2);
|
||||
}
|
||||
else if (typeof t1 === "string") {
|
||||
return Comparison.LessThan;
|
||||
|
||||
if (typeof t1 === "string") {
|
||||
t1 = { messageText: t1 };
|
||||
}
|
||||
else if (typeof t2 === "string") {
|
||||
return Comparison.GreaterThan;
|
||||
if (typeof t2 === "string") {
|
||||
t2 = { messageText: t2 };
|
||||
}
|
||||
let res = compareStringsCaseSensitive(t1.messageText, t2.messageText);
|
||||
const res = compareStringsCaseSensitive(t1.messageText, t2.messageText);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
if (!t1.next && !t2.next) {
|
||||
|
||||
return compareMessageChain(t1.next, t2.next);
|
||||
}
|
||||
|
||||
// First compare by size of the message chain,
|
||||
// then compare by content of the message chain.
|
||||
function compareMessageChain(
|
||||
c1: DiagnosticMessageChain[] | undefined,
|
||||
c2: DiagnosticMessageChain[] | undefined,
|
||||
): Comparison {
|
||||
if (c1 === undefined && c2 === undefined) {
|
||||
return Comparison.EqualTo;
|
||||
}
|
||||
if (!t1.next) {
|
||||
return Comparison.LessThan;
|
||||
}
|
||||
if (!t2.next) {
|
||||
if (c1 === undefined) {
|
||||
return Comparison.GreaterThan;
|
||||
}
|
||||
const len = Math.min(t1.next.length, t2.next.length);
|
||||
for (let i = 0; i < len; i++) {
|
||||
res = compareMessageText(t1.next[i], t2.next[i]);
|
||||
if (c2 === undefined) {
|
||||
return Comparison.LessThan;
|
||||
}
|
||||
|
||||
return compareMessageChainSize(c1, c2) || compareMessageChainContent(c1, c2);
|
||||
}
|
||||
|
||||
function compareMessageChainSize(
|
||||
c1: DiagnosticMessageChain[] | undefined,
|
||||
c2: DiagnosticMessageChain[] | undefined,
|
||||
): Comparison {
|
||||
if (c1 === undefined && c2 === undefined) {
|
||||
return Comparison.EqualTo;
|
||||
}
|
||||
if (c1 === undefined) {
|
||||
return Comparison.GreaterThan;
|
||||
}
|
||||
if (c2 === undefined) {
|
||||
return Comparison.LessThan;
|
||||
}
|
||||
|
||||
let res = compareValues(c2.length, c1.length);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (let i = 0; i < c2.length; i++) {
|
||||
res = compareMessageChainSize(c1[i].next, c2[i].next);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (t1.next.length < t2.next.length) {
|
||||
return Comparison.LessThan;
|
||||
}
|
||||
else if (t1.next.length > t2.next.length) {
|
||||
return Comparison.GreaterThan;
|
||||
|
||||
return Comparison.EqualTo;
|
||||
}
|
||||
|
||||
// Assumes the two chains have the same shape.
|
||||
function compareMessageChainContent(
|
||||
c1: DiagnosticMessageChain[],
|
||||
c2: DiagnosticMessageChain[],
|
||||
): Comparison {
|
||||
let res;
|
||||
for (let i = 0; i < c2.length; i++) {
|
||||
res = compareStringsCaseSensitive(c1[i].messageText, c2[i].messageText);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
if (c1[i].next === undefined) {
|
||||
continue;
|
||||
}
|
||||
res = compareMessageChainContent(c1[i].next!, c2[i].next!);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return Comparison.EqualTo;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function diagnosticsEqualityComparer(d1: Diagnostic, d2: Diagnostic): boolean {
|
||||
return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) === Comparison.EqualTo &&
|
||||
compareValues(d1.start, d2.start) === Comparison.EqualTo &&
|
||||
compareValues(d1.length, d2.length) === Comparison.EqualTo &&
|
||||
compareValues(d1.code, d2.code) === Comparison.EqualTo &&
|
||||
messageTextEqualityComparer(d1.messageText, d2.messageText);
|
||||
}
|
||||
|
||||
function messageTextEqualityComparer(m1: string | DiagnosticMessageChain, m2: string | DiagnosticMessageChain): boolean {
|
||||
const t1 = typeof m1 === "string" ? m1 : m1.messageText;
|
||||
const t2 = typeof m2 === "string" ? m2 : m2.messageText;
|
||||
return compareStringsCaseSensitive(t1, t2) === Comparison.EqualTo;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getLanguageVariant(scriptKind: ScriptKind) {
|
||||
// .tsx and .jsx files are treated as jsx language variant.
|
||||
|
||||
@ -49,6 +49,7 @@ import {
|
||||
Decorator,
|
||||
Diagnostic,
|
||||
Diagnostics,
|
||||
diagnosticsEqualityComparer,
|
||||
ElementAccessChain,
|
||||
ElementAccessExpression,
|
||||
emptyArray,
|
||||
@ -304,7 +305,7 @@ export function isExternalModuleNameRelative(moduleName: string): boolean {
|
||||
}
|
||||
|
||||
export function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: readonly T[]): SortedReadonlyArray<T> {
|
||||
return sortAndDeduplicate<T>(diagnostics, compareDiagnostics);
|
||||
return sortAndDeduplicate<T>(diagnostics, compareDiagnostics, diagnosticsEqualityComparer);
|
||||
}
|
||||
|
||||
export function getDefaultLibFileName(options: CompilerOptions): string {
|
||||
|
||||
@ -1340,7 +1340,7 @@ function completionInfoFromData(
|
||||
!uniqueNames.has(keywordEntry.name)
|
||||
) {
|
||||
uniqueNames.add(keywordEntry.name);
|
||||
insertSorted(entries, keywordEntry, compareCompletionEntries, /*allowDuplicates*/ true);
|
||||
insertSorted(entries, keywordEntry, compareCompletionEntries, /*equalityComparer*/ undefined, /*allowDuplicates*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1348,14 +1348,14 @@ function completionInfoFromData(
|
||||
for (const keywordEntry of getContextualKeywords(contextToken, position)) {
|
||||
if (!uniqueNames.has(keywordEntry.name)) {
|
||||
uniqueNames.add(keywordEntry.name);
|
||||
insertSorted(entries, keywordEntry, compareCompletionEntries, /*allowDuplicates*/ true);
|
||||
insertSorted(entries, keywordEntry, compareCompletionEntries, /*equalityComparer*/ undefined, /*allowDuplicates*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
for (const literal of literals) {
|
||||
const literalEntry = createCompletionEntryForLiteral(sourceFile, preferences, literal);
|
||||
uniqueNames.add(literalEntry.name);
|
||||
insertSorted(entries, literalEntry, compareCompletionEntries, /*allowDuplicates*/ true);
|
||||
insertSorted(entries, literalEntry, compareCompletionEntries, /*equalityComparer*/ undefined, /*allowDuplicates*/ true);
|
||||
}
|
||||
|
||||
if (!isChecked) {
|
||||
@ -2630,7 +2630,7 @@ export function getCompletionEntriesFromSymbols(
|
||||
/** True for locals; false for globals, module exports from other files, `this.` completions. */
|
||||
const shouldShadowLaterSymbols = (!origin || originIsTypeOnlyAlias(origin)) && !(symbol.parent === undefined && !some(symbol.declarations, d => d.getSourceFile() === location.getSourceFile()));
|
||||
uniques.set(name, shouldShadowLaterSymbols);
|
||||
insertSorted(entries, entry, compareCompletionEntries, /*allowDuplicates*/ true);
|
||||
insertSorted(entries, entry, compareCompletionEntries, /*equalityComparer*/ undefined, /*allowDuplicates*/ true);
|
||||
}
|
||||
|
||||
log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (timestamp() - start));
|
||||
|
||||
@ -6,6 +6,7 @@ import "./unittests/comments";
|
||||
import "./unittests/compilerCore";
|
||||
import "./unittests/convertToBase64";
|
||||
import "./unittests/customTransforms";
|
||||
import "./unittests/diagnosticCollection";
|
||||
import "./unittests/factory";
|
||||
import "./unittests/incrementalParser";
|
||||
import "./unittests/jsDocParsing";
|
||||
|
||||
120
src/testRunner/unittests/diagnosticCollection.ts
Normal file
120
src/testRunner/unittests/diagnosticCollection.ts
Normal file
@ -0,0 +1,120 @@
|
||||
import * as ts from "../_namespaces/ts";
|
||||
|
||||
describe("unittests:: internalApi:: diagnosticCollection", () => {
|
||||
describe("add", () => {
|
||||
it("keeps equivalent diagnostic with elaboration", () => {
|
||||
const collection = ts.createDiagnosticCollection();
|
||||
const file = ts.createSourceFile("index.ts", "const x = 1", ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
|
||||
const node = file.statements[0];
|
||||
|
||||
const dy = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "y");
|
||||
const da = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "a");
|
||||
collection.add(dy);
|
||||
collection.add(da);
|
||||
|
||||
const chain = ts.chainDiagnosticMessages(
|
||||
ts.chainDiagnosticMessages(/*details*/ undefined, ts.Diagnostics.Did_you_mean_0, "x"),
|
||||
ts.Diagnostics.Cannot_find_name_0,
|
||||
"y",
|
||||
);
|
||||
const dyBetter = ts.createDiagnosticForNodeFromMessageChain(file, node, chain);
|
||||
|
||||
collection.add(dyBetter);
|
||||
const result = collection.getDiagnostics();
|
||||
assert.deepEqual(result, [da, dyBetter]);
|
||||
});
|
||||
|
||||
it("keeps equivalent diagnostic with deeper elaboration", () => {
|
||||
const collection = ts.createDiagnosticCollection();
|
||||
const file = ts.createSourceFile("index.ts", "const x = 1", ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
|
||||
const node = file.statements[0];
|
||||
|
||||
const da = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "a");
|
||||
collection.add(da);
|
||||
|
||||
const chain = ts.chainDiagnosticMessages(
|
||||
ts.chainDiagnosticMessages(/*details*/ undefined, ts.Diagnostics.Did_you_mean_0, "a"),
|
||||
ts.Diagnostics.Cannot_find_name_0,
|
||||
"y",
|
||||
);
|
||||
const dy = ts.createDiagnosticForNodeFromMessageChain(file, node, chain);
|
||||
collection.add(dy);
|
||||
|
||||
const chainBetter = ts.chainDiagnosticMessages(
|
||||
ts.chainDiagnosticMessages(
|
||||
ts.chainDiagnosticMessages(/*details*/ undefined, ts.Diagnostics.Did_you_mean_0, "x"),
|
||||
ts.Diagnostics.Did_you_mean_0,
|
||||
"b",
|
||||
),
|
||||
ts.Diagnostics.Cannot_find_name_0,
|
||||
"y",
|
||||
);
|
||||
const dyBetter = ts.createDiagnosticForNodeFromMessageChain(file, node, chainBetter);
|
||||
|
||||
collection.add(dyBetter);
|
||||
const result = collection.getDiagnostics();
|
||||
assert.deepEqual(result, [da, dyBetter]);
|
||||
});
|
||||
|
||||
it("doesn't keep equivalent diagnostic with no elaboration", () => {
|
||||
const collection = ts.createDiagnosticCollection();
|
||||
const file = ts.createSourceFile("index.ts", "const x = 1", ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
|
||||
const node = file.statements[0];
|
||||
|
||||
const chain = ts.chainDiagnosticMessages(
|
||||
ts.chainDiagnosticMessages(/*details*/ undefined, ts.Diagnostics.Did_you_mean_0, "x"),
|
||||
ts.Diagnostics.Cannot_find_name_0,
|
||||
"y",
|
||||
);
|
||||
const dyBetter = ts.createDiagnosticForNodeFromMessageChain(file, node, chain);
|
||||
const da = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "a");
|
||||
collection.add(da);
|
||||
collection.add(dyBetter);
|
||||
|
||||
const dy = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "y");
|
||||
collection.add(dy);
|
||||
const result = collection.getDiagnostics();
|
||||
assert.deepEqual(result, [da, dyBetter]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("lookup", () => {
|
||||
it("returns an equivalent diagnostic with more elaboration", () => {
|
||||
const collection = ts.createDiagnosticCollection();
|
||||
const file = ts.createSourceFile("index.ts", "const x = 1", ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
|
||||
const node = file.statements[0];
|
||||
|
||||
const da = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "a");
|
||||
collection.add(da);
|
||||
|
||||
const chain = ts.chainDiagnosticMessages(
|
||||
ts.chainDiagnosticMessages(/*details*/ undefined, ts.Diagnostics.Did_you_mean_0, "x"),
|
||||
ts.Diagnostics.Cannot_find_name_0,
|
||||
"y",
|
||||
);
|
||||
const dyBetter = ts.createDiagnosticForNodeFromMessageChain(file, node, chain);
|
||||
collection.add(dyBetter);
|
||||
|
||||
const dy = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "y");
|
||||
assert.equal(collection.lookup(dy), dyBetter);
|
||||
});
|
||||
it("doesn't return an equivalent diagnostic with less elaboration", () => {
|
||||
const collection = ts.createDiagnosticCollection();
|
||||
const file = ts.createSourceFile("index.ts", "const x = 1", ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
|
||||
const node = file.statements[0];
|
||||
|
||||
const da = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "a");
|
||||
collection.add(da);
|
||||
const dy = ts.createDiagnosticForNode(node, ts.Diagnostics.Cannot_find_name_0, "y");
|
||||
collection.add(dy);
|
||||
|
||||
const chain = ts.chainDiagnosticMessages(
|
||||
ts.chainDiagnosticMessages(/*details*/ undefined, ts.Diagnostics.Did_you_mean_0, "x"),
|
||||
ts.Diagnostics.Cannot_find_name_0,
|
||||
"y",
|
||||
);
|
||||
const dyBetter = ts.createDiagnosticForNodeFromMessageChain(file, node, chain);
|
||||
assert.equal(collection.lookup(dyBetter), undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,6 +1,6 @@
|
||||
destructuringAssignmentWithDefault2.ts(11,4): error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
destructuringAssignmentWithDefault2.ts(11,4): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
|
||||
Type 'undefined' is not assignable to type 'number'.
|
||||
destructuringAssignmentWithDefault2.ts(11,4): error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
destructuringAssignmentWithDefault2.ts(12,7): error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
destructuringAssignmentWithDefault2.ts(13,7): error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
|
||||
@ -18,10 +18,10 @@ destructuringAssignmentWithDefault2.ts(13,7): error TS2322: Type 'undefined' is
|
||||
// Should be error
|
||||
({ x = undefined } = a);
|
||||
~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
~
|
||||
!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
({ x: x = undefined } = a);
|
||||
~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
duplicateErrorClassExpression.ts(17,5): error TS2416: Property 'foo' in type 'Derived' is not assignable to the same property in base type 'Base'.
|
||||
Type 'ComplicatedTypeDerived' is not assignable to type 'ComplicatedTypeBase'.
|
||||
'string' index signatures are incompatible.
|
||||
Property 'a' is missing in type 'ADerived' but required in type 'ABase'.
|
||||
duplicateErrorClassExpression.ts(20,5): error TS2538: Type 'typeof Derived' cannot be used as an index type.
|
||||
|
||||
|
||||
==== duplicateErrorClassExpression.ts (2 errors) ====
|
||||
interface ComplicatedTypeBase {
|
||||
[s: string]: ABase;
|
||||
}
|
||||
interface ComplicatedTypeDerived {
|
||||
[s: string]: ADerived;
|
||||
}
|
||||
interface ABase {
|
||||
a: string;
|
||||
}
|
||||
interface ADerived {
|
||||
b: string;
|
||||
}
|
||||
class Base {
|
||||
foo!: ComplicatedTypeBase;
|
||||
}
|
||||
const x = class Derived extends Base {
|
||||
foo!: ComplicatedTypeDerived;
|
||||
~~~
|
||||
!!! error TS2416: Property 'foo' in type 'Derived' is not assignable to the same property in base type 'Base'.
|
||||
!!! error TS2416: Type 'ComplicatedTypeDerived' is not assignable to type 'ComplicatedTypeBase'.
|
||||
!!! error TS2416: 'string' index signatures are incompatible.
|
||||
!!! error TS2416: Property 'a' is missing in type 'ADerived' but required in type 'ABase'.
|
||||
!!! related TS2728 duplicateErrorClassExpression.ts:8:5: 'a' is declared here.
|
||||
}
|
||||
let obj: { 3: string } = { 3: "three" };
|
||||
obj[x];
|
||||
~
|
||||
!!! error TS2538: Type 'typeof Derived' cannot be used as an index type.
|
||||
55
tests/baselines/reference/duplicateErrorClassExpression.js
Normal file
55
tests/baselines/reference/duplicateErrorClassExpression.js
Normal file
@ -0,0 +1,55 @@
|
||||
//// [tests/cases/compiler/duplicateErrorClassExpression.ts] ////
|
||||
|
||||
//// [duplicateErrorClassExpression.ts]
|
||||
interface ComplicatedTypeBase {
|
||||
[s: string]: ABase;
|
||||
}
|
||||
interface ComplicatedTypeDerived {
|
||||
[s: string]: ADerived;
|
||||
}
|
||||
interface ABase {
|
||||
a: string;
|
||||
}
|
||||
interface ADerived {
|
||||
b: string;
|
||||
}
|
||||
class Base {
|
||||
foo!: ComplicatedTypeBase;
|
||||
}
|
||||
const x = class Derived extends Base {
|
||||
foo!: ComplicatedTypeDerived;
|
||||
}
|
||||
let obj: { 3: string } = { 3: "three" };
|
||||
obj[x];
|
||||
|
||||
//// [duplicateErrorClassExpression.js]
|
||||
"use strict";
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
var Base = /** @class */ (function () {
|
||||
function Base() {
|
||||
}
|
||||
return Base;
|
||||
}());
|
||||
var x = /** @class */ (function (_super) {
|
||||
__extends(Derived, _super);
|
||||
function Derived() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return Derived;
|
||||
}(Base));
|
||||
var obj = { 3: "three" };
|
||||
obj[x];
|
||||
@ -0,0 +1,54 @@
|
||||
//// [tests/cases/compiler/duplicateErrorClassExpression.ts] ////
|
||||
|
||||
=== duplicateErrorClassExpression.ts ===
|
||||
interface ComplicatedTypeBase {
|
||||
>ComplicatedTypeBase : Symbol(ComplicatedTypeBase, Decl(duplicateErrorClassExpression.ts, 0, 0))
|
||||
|
||||
[s: string]: ABase;
|
||||
>s : Symbol(s, Decl(duplicateErrorClassExpression.ts, 1, 5))
|
||||
>ABase : Symbol(ABase, Decl(duplicateErrorClassExpression.ts, 5, 1))
|
||||
}
|
||||
interface ComplicatedTypeDerived {
|
||||
>ComplicatedTypeDerived : Symbol(ComplicatedTypeDerived, Decl(duplicateErrorClassExpression.ts, 2, 1))
|
||||
|
||||
[s: string]: ADerived;
|
||||
>s : Symbol(s, Decl(duplicateErrorClassExpression.ts, 4, 5))
|
||||
>ADerived : Symbol(ADerived, Decl(duplicateErrorClassExpression.ts, 8, 1))
|
||||
}
|
||||
interface ABase {
|
||||
>ABase : Symbol(ABase, Decl(duplicateErrorClassExpression.ts, 5, 1))
|
||||
|
||||
a: string;
|
||||
>a : Symbol(ABase.a, Decl(duplicateErrorClassExpression.ts, 6, 17))
|
||||
}
|
||||
interface ADerived {
|
||||
>ADerived : Symbol(ADerived, Decl(duplicateErrorClassExpression.ts, 8, 1))
|
||||
|
||||
b: string;
|
||||
>b : Symbol(ADerived.b, Decl(duplicateErrorClassExpression.ts, 9, 20))
|
||||
}
|
||||
class Base {
|
||||
>Base : Symbol(Base, Decl(duplicateErrorClassExpression.ts, 11, 1))
|
||||
|
||||
foo!: ComplicatedTypeBase;
|
||||
>foo : Symbol(Base.foo, Decl(duplicateErrorClassExpression.ts, 12, 12))
|
||||
>ComplicatedTypeBase : Symbol(ComplicatedTypeBase, Decl(duplicateErrorClassExpression.ts, 0, 0))
|
||||
}
|
||||
const x = class Derived extends Base {
|
||||
>x : Symbol(x, Decl(duplicateErrorClassExpression.ts, 15, 5))
|
||||
>Derived : Symbol(Derived, Decl(duplicateErrorClassExpression.ts, 15, 9))
|
||||
>Base : Symbol(Base, Decl(duplicateErrorClassExpression.ts, 11, 1))
|
||||
|
||||
foo!: ComplicatedTypeDerived;
|
||||
>foo : Symbol(Derived.foo, Decl(duplicateErrorClassExpression.ts, 15, 38))
|
||||
>ComplicatedTypeDerived : Symbol(ComplicatedTypeDerived, Decl(duplicateErrorClassExpression.ts, 2, 1))
|
||||
}
|
||||
let obj: { 3: string } = { 3: "three" };
|
||||
>obj : Symbol(obj, Decl(duplicateErrorClassExpression.ts, 18, 3))
|
||||
>3 : Symbol(3, Decl(duplicateErrorClassExpression.ts, 18, 10))
|
||||
>3 : Symbol(3, Decl(duplicateErrorClassExpression.ts, 18, 26))
|
||||
|
||||
obj[x];
|
||||
>obj : Symbol(obj, Decl(duplicateErrorClassExpression.ts, 18, 3))
|
||||
>x : Symbol(x, Decl(duplicateErrorClassExpression.ts, 15, 5))
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
//// [tests/cases/compiler/duplicateErrorClassExpression.ts] ////
|
||||
|
||||
=== duplicateErrorClassExpression.ts ===
|
||||
interface ComplicatedTypeBase {
|
||||
[s: string]: ABase;
|
||||
>s : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
interface ComplicatedTypeDerived {
|
||||
[s: string]: ADerived;
|
||||
>s : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
interface ABase {
|
||||
a: string;
|
||||
>a : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
interface ADerived {
|
||||
b: string;
|
||||
>b : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
class Base {
|
||||
>Base : Base
|
||||
> : ^^^^
|
||||
|
||||
foo!: ComplicatedTypeBase;
|
||||
>foo : ComplicatedTypeBase
|
||||
> : ^^^^^^^^^^^^^^^^^^^
|
||||
}
|
||||
const x = class Derived extends Base {
|
||||
>x : typeof Derived
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>class Derived extends Base { foo!: ComplicatedTypeDerived;} : typeof Derived
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>Derived : typeof Derived
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>Base : Base
|
||||
> : ^^^^
|
||||
|
||||
foo!: ComplicatedTypeDerived;
|
||||
>foo : ComplicatedTypeDerived
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^
|
||||
}
|
||||
let obj: { 3: string } = { 3: "three" };
|
||||
>obj : { 3: string; }
|
||||
> : ^^^^^ ^^^
|
||||
>3 : string
|
||||
> : ^^^^^^
|
||||
>{ 3: "three" } : { 3: string; }
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>3 : string
|
||||
> : ^^^^^^
|
||||
>"three" : "three"
|
||||
> : ^^^^^^^
|
||||
|
||||
obj[x];
|
||||
>obj[x] : any
|
||||
> : ^^^
|
||||
>obj : { 3: string; }
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>x : typeof Derived
|
||||
> : ^^^^^^^^^^^^^^
|
||||
|
||||
@ -1,17 +1,13 @@
|
||||
multipleDefaultExports05.ts(1,22): error TS2528: A module cannot have multiple default exports.
|
||||
multipleDefaultExports05.ts(1,22): error TS2528: A module cannot have multiple default exports.
|
||||
multipleDefaultExports05.ts(3,22): error TS2528: A module cannot have multiple default exports.
|
||||
multipleDefaultExports05.ts(5,22): error TS2528: A module cannot have multiple default exports.
|
||||
|
||||
|
||||
==== multipleDefaultExports05.ts (4 errors) ====
|
||||
==== multipleDefaultExports05.ts (3 errors) ====
|
||||
export default class AA1 {}
|
||||
~~~
|
||||
!!! error TS2528: A module cannot have multiple default exports.
|
||||
!!! related TS2753 multipleDefaultExports05.ts:3:22: Another export default is here.
|
||||
~~~
|
||||
!!! error TS2528: A module cannot have multiple default exports.
|
||||
!!! related TS2753 multipleDefaultExports05.ts:5:22: Another export default is here.
|
||||
|
||||
export default class BB1 {}
|
||||
~~~
|
||||
|
||||
22
tests/cases/compiler/duplicateErrorClassExpression.ts
Normal file
22
tests/cases/compiler/duplicateErrorClassExpression.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// @strict: true
|
||||
|
||||
interface ComplicatedTypeBase {
|
||||
[s: string]: ABase;
|
||||
}
|
||||
interface ComplicatedTypeDerived {
|
||||
[s: string]: ADerived;
|
||||
}
|
||||
interface ABase {
|
||||
a: string;
|
||||
}
|
||||
interface ADerived {
|
||||
b: string;
|
||||
}
|
||||
class Base {
|
||||
foo!: ComplicatedTypeBase;
|
||||
}
|
||||
const x = class Derived extends Base {
|
||||
foo!: ComplicatedTypeDerived;
|
||||
}
|
||||
let obj: { 3: string } = { 3: "three" };
|
||||
obj[x];
|
||||
Loading…
x
Reference in New Issue
Block a user