Merge remote-tracking branch 'origin/master' into numericPropertyAccess

This commit is contained in:
Daniel Rosenwasser
2018-12-11 16:52:23 -08:00
117 changed files with 1888 additions and 405 deletions

View File

@@ -1419,12 +1419,18 @@ namespace ts {
}
}
break;
case SyntaxKind.ArrowFunction:
// when targeting ES6 or higher there is no 'arguments' in an arrow function
// for lower compile targets the resolved symbol is used to emit an error
if (compilerOptions.target! >= ScriptTarget.ES2015) {
break;
}
// falls through
case SyntaxKind.MethodDeclaration:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
if (meaning & SymbolFlags.Variable && name === "arguments") {
result = argumentsSymbol;
break loop;
@@ -4709,6 +4715,10 @@ namespace ts {
return prop ? getTypeOfSymbol(prop) : undefined;
}
function getTypeOfPropertyOrIndexSignature(type: Type, name: __String): Type {
return getTypeOfPropertyOfType(type, name) || isNumericLiteralName(name) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String) || unknownType;
}
function isTypeAny(type: Type | undefined) {
return type && (type.flags & TypeFlags.Any) !== 0;
}
@@ -12168,10 +12178,6 @@ namespace ts {
return result;
}
function getConstraintForRelation(type: Type) {
return relation === definitelyAssignableRelation ? undefined : getConstraintOfType(type);
}
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary {
const flags = source.flags & target.flags;
if (relation === identityRelation && !(flags & TypeFlags.Object)) {
@@ -12304,24 +12310,26 @@ namespace ts {
return result;
}
}
const constraint = getConstraintForRelation(<TypeParameter>source);
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.AnyOrUnknown)) {
// A type variable with no constraint is not related to the non-primitive object type.
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
if (relation !== definitelyAssignableRelation) {
const constraint = getConstraintOfType(<TypeParameter>source);
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
// A type variable with no constraint is not related to the non-primitive object type.
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
errorInfo = saveErrorInfo;
return result;
}
}
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
errorInfo = saveErrorInfo;
return result;
}
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
errorInfo = saveErrorInfo;
return result;
}
}
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
errorInfo = saveErrorInfo;
return result;
}
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
errorInfo = saveErrorInfo;
return result;
}
}
else if (source.flags & TypeFlags.Index) {
if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) {
@@ -12473,10 +12481,10 @@ namespace ts {
return propertiesIdenticalTo(source, target);
}
const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source);
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties);
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
if (unmatchedProperty) {
if (reportErrors) {
const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties));
const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
@@ -13900,7 +13908,7 @@ namespace ts {
return getTypeFromInference(inference);
}
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean) {
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean) {
const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(<IntersectionType>target) : getPropertiesOfObjectType(target);
for (const targetProp of properties) {
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) {
@@ -13908,12 +13916,21 @@ namespace ts {
if (!sourceProp) {
yield targetProp;
}
else if (matchDiscriminantProperties) {
const targetType = getTypeOfSymbol(targetProp);
if (targetType.flags & TypeFlags.Unit) {
const sourceType = getTypeOfSymbol(sourceProp);
if (!(sourceType.flags & TypeFlags.Any || getRegularTypeOfLiteralType(sourceType) === getRegularTypeOfLiteralType(targetType))) {
yield targetProp;
}
}
}
}
}
}
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean): Symbol | undefined {
return getUnmatchedProperties(source, target, requireOptionalProperties).next().value;
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): Symbol | undefined {
return getUnmatchedProperties(source, target, requireOptionalProperties, matchDiscriminantProperties).next().value;
}
function tupleTypesDefinitelyUnrelated(source: TupleTypeReference, target: TupleTypeReference) {
@@ -13925,7 +13942,8 @@ namespace ts {
// Two tuple types with incompatible arities are definitely unrelated.
// Two object types that each have a property that is unmatched in the other are definitely unrelated.
return isTupleType(source) && isTupleType(target) && tupleTypesDefinitelyUnrelated(source, target) ||
!!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) && !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false);
!!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true) &&
!!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true);
}
function getTypeFromInference(inference: InferenceInfo) {
@@ -15643,7 +15661,7 @@ namespace ts {
}
const propType = getTypeOfPropertyOfType(type, propName);
const narrowedPropType = propType && narrowType(propType);
return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOfType(t, propName)!, narrowedPropType!));
return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOrIndexSignature(t, propName), narrowedPropType!));
}
function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type {
@@ -19872,14 +19890,31 @@ namespace ts {
}
function getTypeArgumentArityError(node: Node, signatures: ReadonlyArray<Signature>, typeArguments: NodeArray<TypeNode>) {
let min = Infinity;
let max = -Infinity;
for (const sig of signatures) {
min = Math.min(min, getMinTypeArgumentCount(sig.typeParameters));
max = Math.max(max, length(sig.typeParameters));
const argCount = typeArguments.length;
// No overloads exist
if (signatures.length === 1) {
const sig = signatures[0];
const min = getMinTypeArgumentCount(sig.typeParameters);
const max = length(sig.typeParameters);
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min , argCount);
}
const paramCount = min === max ? min : min + "-" + max;
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length);
// Overloads exist
let belowArgCount = -Infinity;
let aboveArgCount = Infinity;
for (const sig of signatures) {
const min = getMinTypeArgumentCount(sig.typeParameters);
const max = length(sig.typeParameters);
if (min > argCount) {
aboveArgCount = Math.min(aboveArgCount, min);
}
else if (max < argCount) {
belowArgCount = Math.max(belowArgCount, max);
}
}
if (belowArgCount !== -Infinity && aboveArgCount !== Infinity) {
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount);
}
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
}
function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean, fallbackError?: DiagnosticMessage): Signature {
@@ -23633,7 +23668,6 @@ namespace ts {
break;
}
}
checkGrammarForDisallowedTrailingComma(node.elementTypes);
forEach(node.elementTypes, checkSourceElement);
}

View File

@@ -2165,6 +2165,10 @@ namespace ts {
}
export function fill<T>(length: number, cb: (index: number) => T): T[] {
return new Array(length).fill(0).map((_, i) => cb(i));
const result = Array<T>(length);
for (let i = 0; i < length; i++) {
result[i] = cb(i);
}
return result;
}
}

View File

@@ -1011,6 +1011,10 @@
"category": "Message",
"code": 1350
},
"An identifier or keyword cannot immediately follow a numeric literal.": {
"category": "Error",
"code": 1351
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -2529,6 +2533,10 @@
"category": "Error",
"code": 2742
},
"No overload expects {0} type arguments, but overloads do exist that expect either {1} or {2} type arguments.": {
"category": "Error",
"code": 2743
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View File

@@ -40,18 +40,18 @@ namespace ts {
type Recurser = <T>(obj: unknown, name: string, cbOk: () => T, cbFail: (isCircularReference: boolean, keyStack: ReadonlyArray<string>) => T) => T;
function getRecurser(): Recurser {
const seen = new Set<unknown>();
const seen: unknown[] = [];
const nameStack: string[] = [];
return (obj, name, cbOk, cbFail) => {
if (seen.has(obj) || nameStack.length > 4) {
return cbFail(seen.has(obj), nameStack);
if (seen.indexOf(obj) !== -1 || nameStack.length > 4) {
return cbFail(seen.indexOf(obj) !== -1, nameStack);
}
seen.add(obj);
seen.push(obj);
nameStack.push(name);
const res = cbOk();
nameStack.pop();
seen.delete(obj);
seen.pop();
return res;
};
}
@@ -104,8 +104,8 @@ namespace ts {
key === "constructor" ? undefined : getValueInfo(key, value, recurser));
}
const ignoredProperties: ReadonlySet<string> = new Set(["arguments", "caller", "constructor", "eval", "super_"]);
const reservedFunctionProperties: ReadonlySet<string> = new Set(Object.getOwnPropertyNames(noop));
const ignoredProperties: ReadonlyArray<string> = ["arguments", "caller", "constructor", "eval", "super_"];
const reservedFunctionProperties: ReadonlyArray<string> = Object.getOwnPropertyNames(noop);
interface ObjectEntry { readonly key: string; readonly value: unknown; }
function getEntriesOfObject(obj: object): ReadonlyArray<ObjectEntry> {
const seen = createMap<true>();
@@ -114,8 +114,8 @@ namespace ts {
while (!isNullOrUndefined(chain) && chain !== Object.prototype && chain !== Function.prototype) {
for (const key of Object.getOwnPropertyNames(chain)) {
if (!isJsPrivate(key) &&
!ignoredProperties.has(key) &&
(typeof obj !== "function" || !reservedFunctionProperties.has(key)) &&
ignoredProperties.indexOf(key) === -1 &&
(typeof obj !== "function" || reservedFunctionProperties.indexOf(key) === -1) &&
// Don't add property from a higher prototype if it already exists in a lower one
addToSeen(seen, key)) {
const value = safeGetPropertyOfObject(chain, key);
@@ -148,7 +148,7 @@ namespace ts {
}
export function isJsPrivate(name: string): boolean {
return name.startsWith("_");
return startsWith(name, "_");
}
function tryRequire(fileNameToRequire: string): unknown {

View File

@@ -203,7 +203,7 @@ namespace ts.moduleSpecifiers {
return; // Don't want to a package to globally import from itself
}
const target = targets.find(t => compareStrings(t.slice(0, resolved.length + 1), resolved + "/") === Comparison.EqualTo);
const target = find(targets, t => compareStrings(t.slice(0, resolved.length + 1), resolved + "/") === Comparison.EqualTo);
if (target === undefined) return;
const relative = getRelativePathFromDirectory(resolved, target, getCanonicalFileName);

View File

@@ -974,7 +974,9 @@ namespace ts {
else {
result = text.substring(start, end); // No need to use all the fragments; no _ removal needed
}
if (decimalFragment !== undefined || tokenFlags & TokenFlags.Scientific) {
checkForIdentifierStartAfterNumericLiteral();
return {
type: SyntaxKind.NumericLiteral,
value: "" + +result // if value is not an integer, it can be safely coerced to a number
@@ -983,10 +985,22 @@ namespace ts {
else {
tokenValue = result;
const type = checkBigIntSuffix(); // if value is an integer, check whether it is a bigint
checkForIdentifierStartAfterNumericLiteral();
return { type, value: tokenValue };
}
}
function checkForIdentifierStartAfterNumericLiteral() {
if (!isIdentifierStart(text.charCodeAt(pos), languageVersion)) {
return;
}
const identifierStart = pos;
const { length } = scanIdentifierParts();
error(Diagnostics.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal, identifierStart, length);
pos = identifierStart;
}
function scanOctalDigits(): number {
const start = pos;
while (isOctalDigit(text.charCodeAt(pos))) {

View File

@@ -4450,6 +4450,8 @@ namespace FourSlashInterface {
interfaceEntry("ObjectConstructor"),
constEntry("Function"),
interfaceEntry("FunctionConstructor"),
typeEntry("ThisParameterType"),
typeEntry("OmitThisParameter"),
interfaceEntry("CallableFunction"),
interfaceEntry("NewableFunction"),
interfaceEntry("IArguments"),

14
src/lib/es5.d.ts vendored
View File

@@ -295,6 +295,16 @@ interface FunctionConstructor {
declare const Function: FunctionConstructor;
/**
* Extracts the type of the 'this' parameter of a function type, or 'unknown' if the function type has no 'this' parameter.
*/
type ThisParameterType<T> = T extends (this: unknown, ...args: any[]) => any ? unknown : T extends (this: infer U, ...args: any[]) => any ? U : unknown;
/**
* Removes the 'this' parameter from a function type.
*/
type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;
interface CallableFunction extends Function {
/**
* Calls the function with the specified object as the this value and the elements of specified array as the arguments.
@@ -317,7 +327,7 @@ interface CallableFunction extends Function {
* @param thisArg The object to be used as the this object.
* @param args Arguments to bind to the parameters of the function.
*/
bind<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T): (...args: A) => R;
bind<T>(this: T, thisArg: ThisParameterType<T>): OmitThisParameter<T>;
bind<T, A0, A extends any[], R>(this: (this: T, arg0: A0, ...args: A) => R, thisArg: T, arg0: A0): (...args: A) => R;
bind<T, A0, A1, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1): (...args: A) => R;
bind<T, A0, A1, A2, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R;
@@ -347,7 +357,7 @@ interface NewableFunction extends Function {
* @param thisArg The object to be used as the this object.
* @param args Arguments to bind to the parameters of the function.
*/
bind<A extends any[], R>(this: new (...args: A) => R, thisArg: any): new (...args: A) => R;
bind<T>(this: T, thisArg: any): T;
bind<A0, A extends any[], R>(this: new (arg0: A0, ...args: A) => R, thisArg: any, arg0: A0): new (...args: A) => R;
bind<A0, A1, A extends any[], R>(this: new (arg0: A0, arg1: A1, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1): new (...args: A) => R;
bind<A0, A1, A2, A extends any[], R>(this: new (arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2): new (...args: A) => R;

View File

@@ -1428,6 +1428,10 @@ namespace ts.FindAllReferences.Core {
return [{ definition: { type: DefinitionKind.Symbol, symbol: searchSpaceNode.symbol }, references }];
}
function isParameterName(node: Node) {
return node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.Parameter && (<ParameterDeclaration>node.parent).name === node;
}
function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
let searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false);
@@ -1450,7 +1454,7 @@ namespace ts.FindAllReferences.Core {
searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class
break;
case SyntaxKind.SourceFile:
if (isExternalModule(<SourceFile>searchSpaceNode)) {
if (isExternalModule(<SourceFile>searchSpaceNode) || isParameterName(thisOrSuperKeyword)) {
return undefined;
}
// falls through
@@ -1483,7 +1487,7 @@ namespace ts.FindAllReferences.Core {
// and has the appropriate static modifier from the original container.
return container.parent && searchSpaceNode.symbol === container.parent.symbol && (getModifierFlags(container) & ModifierFlags.Static) === staticFlag;
case SyntaxKind.SourceFile:
return container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container);
return container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container) && !isParameterName(node);
}
});
}).map(n => nodeEntry(n));

View File

@@ -45,7 +45,7 @@ namespace ts.Rename {
const moduleSourceFile = find(moduleSymbol.declarations, isSourceFile);
if (!moduleSourceFile) return undefined;
const withoutIndex = node.text.endsWith("/index") || node.text.endsWith("/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index");
const withoutIndex = endsWith(node.text, "/index") || endsWith(node.text, "/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index");
const name = withoutIndex === undefined ? moduleSourceFile.fileName : withoutIndex;
const kind = withoutIndex === undefined ? ScriptElementKind.moduleElement : ScriptElementKind.directory;
const indexAfterLastSlash = node.text.lastIndexOf("/") + 1;

View File

@@ -133,6 +133,11 @@ namespace ts {
if (configFileName) {
const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, sys, reportDiagnostic)!; // TODO: GH#18217
if (commandLineOptions.showConfig) {
if (configParseResult.errors.length !== 0) {
updateReportDiagnostic(configParseResult.options);
configParseResult.errors.forEach(reportDiagnostic);
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
}
// tslint:disable-next-line:no-null-keyword
sys.write(JSON.stringify(convertToTSConfig(configParseResult, configFileName, sys), null, 4) + sys.newLine);
return sys.exit(ExitStatus.Success);

View File

@@ -1,7 +1,7 @@
{
"compilerOptions": {
"pretty": true,
"lib": ["es2015"],
"lib": ["es2015.iterable", "es5"],
"target": "es5",
"rootDir": ".",