Compare commits

...

5 commits

Author SHA1 Message Date
Nathan Shively-Sanders ea1b78db15 Original test passes!
So I'm done, right?
2019-08-13 10:23:01 -07:00
Nathan Shively-Sanders 7f8839d115 Use instance type for constructor return type
I did this in 2 places:

1. Eagerly, in resolveAnonymousTypeMembers, which might not be feasible
in the end since it may lead to circularities when I start supporting
prototype assignments.
2. "Elsewhere", in getJSClassType, which is still called in a smattering
of places, nearly all Very Dangerous workarounds for circularity
problems themselves.

With (1), it is easy to make a copy of call signatures to construct
signatures, altering the return type to be the instance type of the
constructor function.
2019-08-13 08:59:57 -07:00
Nathan Shively-Sanders a40133512f Merge branch 'master' into ctor-funcs-are-classes 2019-08-13 08:31:54 -07:00
Nathan Shively-Sanders c9b6637b37 Basic case sort-of works 2019-08-12 16:29:36 -07:00
Nathan Shively-Sanders 8d92435e7b Rename and add notes
1. Rename Type/DeclaredType functions to TypeSide/ValueSide. For
example, getDeclaredTypeOfSymbol is now getTypeOfSymbolTypeSide, and
getTypeOfSymbol is now getTypeOfSymbolValueSide.

I'm not sure I like these names, so I'm going to work with them for a
while.

2. some notes on how convert constructor functions to classes in the
checker
2019-08-12 09:23:47 -07:00
10 changed files with 473 additions and 265 deletions

View file

@ -227,7 +227,7 @@ namespace ts {
symbol.flags |= symbolFlags;
node.symbol = symbol;
symbol.declarations = append(symbol.declarations, node);
symbol.declarations = appendIfUnique(symbol.declarations, node);
if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) && !symbol.exports) {
symbol.exports = createSymbolTable();
@ -2506,9 +2506,13 @@ namespace ts {
}
if (constructorSymbol) {
// TODO: Modify thisContainer's flags here via addDeclarationToSymbol
// (also for prototype assignments and Object.defineProperty assignments (I think))
// (also for functions annotated with `@constructor`, not sure if the binder correctly visits jsdoc yet)
// Declare a 'member' if the container is an ES5 class or ES6 constructor
constructorSymbol.members = constructorSymbol.members || createSymbolTable();
// It's acceptable for multiple 'this' assignments of the same identifier to occur
addDeclarationToSymbol(constructorSymbol, thisContainer as FunctionDeclaration | FunctionExpression, SymbolFlags.Class);
declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
}
break;

File diff suppressed because it is too large Load diff

View file

@ -3119,7 +3119,7 @@ namespace ts {
export interface TypeChecker {
getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type;
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
getTypeOfSymbolTypeSide(symbol: Symbol): Type;
getPropertiesOfType(type: Type): Symbol[];
getPropertyOfType(type: Type, propertyName: string): Symbol | undefined;
/* @internal */ getTypeOfPropertyOfType(type: Type, propertyName: string): Type | undefined;
@ -3749,9 +3749,9 @@ namespace ts {
export interface SymbolLinks {
immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
target?: Symbol; // Resolved (non-alias) target of an alias
type?: Type; // Type of value symbol
type?: Type; // Type of value side of symbol (variable, parameter, property, object, namespace, etc)
typeType?: Type; // Type of type side of symbol (class, interface, enum, type alias, or type parameter)
uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
@ -4157,12 +4157,12 @@ namespace ts {
// Object type or intersection of object types
export type BaseType = ObjectType | IntersectionType;
export interface InterfaceTypeWithDeclaredMembers extends InterfaceType {
declaredProperties: Symbol[]; // Declared members
declaredCallSignatures: Signature[]; // Declared call signatures
declaredConstructSignatures: Signature[]; // Declared construct signatures
declaredStringIndexInfo?: IndexInfo; // Declared string indexing info
declaredNumberIndexInfo?: IndexInfo; // Declared numeric indexing info
export interface InterfaceTypeWithTypeSideMembers extends InterfaceType {
typeSideProperties: Symbol[]; // Members of type side of symbol
typeSideCallSignatures: Signature[]; // Call signatures of type side of symbol
typeSideConstructSignatures: Signature[]; // Construct signatures of type side of symbol
typeSideStringIndexInfo?: IndexInfo; // String index info of type side of symbol
typeSideNumberIndexInfo?: IndexInfo; // Numeric index info of type side of symbol
}
/**

View file

@ -2615,6 +2615,7 @@ namespace ts {
}
export function getEffectiveBaseTypeNode(node: ClassLikeDeclaration | InterfaceDeclaration) {
// TODO: Needs to understand ctor funcs
const baseType = getClassExtendsHeritageElement(node);
if (baseType && isInJSFile(node)) {
// Prefer an @augments tag because it may have type parameters.

View file

@ -132,7 +132,7 @@ namespace ts.codefix {
// Prefer to change the class instead of the interface if they are merged
const classOrInterface = find(symbol.declarations, isClassLike) || find(symbol.declarations, isInterfaceDeclaration);
if (classOrInterface && !program.isSourceFileFromExternalLibrary(classOrInterface.getSourceFile())) {
const makeStatic = ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getDeclaredTypeOfSymbol(symbol);
const makeStatic = ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getTypeOfSymbolTypeSide(symbol);
const declSourceFile = classOrInterface.getSourceFile();
const inJs = isSourceFileJS(declSourceFile);
const call = tryCast(parent.parent, isCallExpression);

View file

@ -297,7 +297,7 @@ namespace ts.SymbolDisplay {
displayParts.push(spacePart());
displayParts.push(operatorPart(SyntaxKind.EqualsToken));
displayParts.push(spacePart());
addRange(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration, TypeFormatFlags.InTypeAlias));
addRange(displayParts, typeToDisplayParts(typeChecker, typeChecker.getTypeOfSymbolTypeSide(symbol), enclosingDeclaration, TypeFormatFlags.InTypeAlias));
}
if (symbolFlags & SymbolFlags.Enum) {
prefixNextMeaning();

View file

@ -0,0 +1,64 @@
=== tests/cases/conformance/salsa/genericPropertiesOfConstructorFunctions.js ===
/**
* @template {string} K
* @template V
* @param {string} ik
* @param {V} iv
*/
function Multimap(ik, iv) {
>Multimap : Symbol(Multimap, Decl(genericPropertiesOfConstructorFunctions.js, 0, 0))
>ik : Symbol(ik, Decl(genericPropertiesOfConstructorFunctions.js, 6, 18))
>iv : Symbol(iv, Decl(genericPropertiesOfConstructorFunctions.js, 6, 21))
/** @type {{ [s: string]: V }} */
this._map = {};
>_map : Symbol(Multimap._map, Decl(genericPropertiesOfConstructorFunctions.js, 6, 27))
// without type annotation
this._map2 = { [ik]: iv };
>_map2 : Symbol(Multimap._map2, Decl(genericPropertiesOfConstructorFunctions.js, 8, 19))
>[ik] : Symbol([ik], Decl(genericPropertiesOfConstructorFunctions.js, 10, 18))
>ik : Symbol(ik, Decl(genericPropertiesOfConstructorFunctions.js, 6, 18))
>iv : Symbol(iv, Decl(genericPropertiesOfConstructorFunctions.js, 6, 21))
};
/** @type {Multimap<"a" | "b", number>} with type annotation */
const map = new Multimap("a", 1);
>map : Symbol(map, Decl(genericPropertiesOfConstructorFunctions.js, 14, 5))
>Multimap : Symbol(Multimap, Decl(genericPropertiesOfConstructorFunctions.js, 0, 0))
// without type annotation
const map2 = new Multimap("m", 2);
>map2 : Symbol(map2, Decl(genericPropertiesOfConstructorFunctions.js, 16, 5))
>Multimap : Symbol(Multimap, Decl(genericPropertiesOfConstructorFunctions.js, 0, 0))
/** @type {number} */
var n = map._map['hi']
>n : Symbol(n, Decl(genericPropertiesOfConstructorFunctions.js, 19, 3), Decl(genericPropertiesOfConstructorFunctions.js, 21, 3), Decl(genericPropertiesOfConstructorFunctions.js, 23, 3), Decl(genericPropertiesOfConstructorFunctions.js, 25, 3))
>map._map : Symbol(Multimap._map, Decl(genericPropertiesOfConstructorFunctions.js, 6, 27))
>map : Symbol(map, Decl(genericPropertiesOfConstructorFunctions.js, 14, 5))
>_map : Symbol(Multimap._map, Decl(genericPropertiesOfConstructorFunctions.js, 6, 27))
/** @type {number} */
var n = map._map2['hi']
>n : Symbol(n, Decl(genericPropertiesOfConstructorFunctions.js, 19, 3), Decl(genericPropertiesOfConstructorFunctions.js, 21, 3), Decl(genericPropertiesOfConstructorFunctions.js, 23, 3), Decl(genericPropertiesOfConstructorFunctions.js, 25, 3))
>map._map2 : Symbol(Multimap._map2, Decl(genericPropertiesOfConstructorFunctions.js, 8, 19))
>map : Symbol(map, Decl(genericPropertiesOfConstructorFunctions.js, 14, 5))
>_map2 : Symbol(Multimap._map2, Decl(genericPropertiesOfConstructorFunctions.js, 8, 19))
/** @type {number} */
var n = map2._map['hi']
>n : Symbol(n, Decl(genericPropertiesOfConstructorFunctions.js, 19, 3), Decl(genericPropertiesOfConstructorFunctions.js, 21, 3), Decl(genericPropertiesOfConstructorFunctions.js, 23, 3), Decl(genericPropertiesOfConstructorFunctions.js, 25, 3))
>map2._map : Symbol(Multimap._map, Decl(genericPropertiesOfConstructorFunctions.js, 6, 27))
>map2 : Symbol(map2, Decl(genericPropertiesOfConstructorFunctions.js, 16, 5))
>_map : Symbol(Multimap._map, Decl(genericPropertiesOfConstructorFunctions.js, 6, 27))
/** @type {number} */
var n = map._map2['hi']
>n : Symbol(n, Decl(genericPropertiesOfConstructorFunctions.js, 19, 3), Decl(genericPropertiesOfConstructorFunctions.js, 21, 3), Decl(genericPropertiesOfConstructorFunctions.js, 23, 3), Decl(genericPropertiesOfConstructorFunctions.js, 25, 3))
>map._map2 : Symbol(Multimap._map2, Decl(genericPropertiesOfConstructorFunctions.js, 8, 19))
>map : Symbol(map, Decl(genericPropertiesOfConstructorFunctions.js, 14, 5))
>_map2 : Symbol(Multimap._map2, Decl(genericPropertiesOfConstructorFunctions.js, 8, 19))

View file

@ -0,0 +1,86 @@
=== tests/cases/conformance/salsa/genericPropertiesOfConstructorFunctions.js ===
/**
* @template {string} K
* @template V
* @param {string} ik
* @param {V} iv
*/
function Multimap(ik, iv) {
>Multimap : typeof Multimap
>ik : string
>iv : V
/** @type {{ [s: string]: V }} */
this._map = {};
>this._map = {} : {}
>this._map : any
>this : any
>_map : any
>{} : {}
// without type annotation
this._map2 = { [ik]: iv };
>this._map2 = { [ik]: iv } : { [x: string]: V; }
>this._map2 : any
>this : any
>_map2 : any
>{ [ik]: iv } : { [x: string]: V; }
>[ik] : V
>ik : string
>iv : V
};
/** @type {Multimap<"a" | "b", number>} with type annotation */
const map = new Multimap("a", 1);
>map : Multimap<"a" | "b", number>
>new Multimap("a", 1) : Multimap<"a" | "b", number>
>Multimap : typeof Multimap
>"a" : "a"
>1 : 1
// without type annotation
const map2 = new Multimap("m", 2);
>map2 : Multimap<string, number>
>new Multimap("m", 2) : Multimap<string, number>
>Multimap : typeof Multimap
>"m" : "m"
>2 : 2
/** @type {number} */
var n = map._map['hi']
>n : number
>map._map['hi'] : number
>map._map : { [s: string]: number; }
>map : Multimap<"a" | "b", number>
>_map : { [s: string]: number; }
>'hi' : "hi"
/** @type {number} */
var n = map._map2['hi']
>n : number
>map._map2['hi'] : number
>map._map2 : { [x: string]: number; }
>map : Multimap<"a" | "b", number>
>_map2 : { [x: string]: number; }
>'hi' : "hi"
/** @type {number} */
var n = map2._map['hi']
>n : number
>map2._map['hi'] : number
>map2._map : { [s: string]: number; }
>map2 : Multimap<string, number>
>_map : { [s: string]: number; }
>'hi' : "hi"
/** @type {number} */
var n = map._map2['hi']
>n : number
>map._map2['hi'] : number
>map._map2 : { [x: string]: number; }
>map : Multimap<"a" | "b", number>
>_map2 : { [x: string]: number; }
>'hi' : "hi"

View file

@ -0,0 +1,32 @@
// @Filename: genericPropertiesOfConstructorFunctions.js
// @allowJs: true
// @checkJs: true
// @noEmit: true
/**
* @template {string} K
* @template V
* @param {string} ik
* @param {V} iv
*/
function Multimap(ik, iv) {
/** @type {{ [s: string]: V }} */
this._map = {};
// without type annotation
this._map2 = { [ik]: iv };
};
/** @type {Multimap<"a" | "b", number>} with type annotation */
const map = new Multimap("a", 1);
// without type annotation
const map2 = new Multimap("m", 2);
/** @type {number} */
var n = map._map['hi']
/** @type {number} */
var n = map._map2['hi']
/** @type {number} */
var n = map2._map['hi']
/** @type {number} */
var n = map._map2['hi']

@ -1 +1 @@
Subproject commit 1e471a007968b7490563b91ed6909ae6046f3fe8
Subproject commit 6fae09b67ec6f7b27259a5c133a6961d05a4161b