Turn 2 type flags into properties#11212
Conversation
1. Instantiated (only modifies anonymous types) 2. ObjectLiteralWithComputedProperties (only modifies [resolved] object types) 3. ThisType (only modifies type parameters) This is needed for object spread and rest, which will each need a type flag. There are 4-5 other likely targets for removal, and I may remove those later.
|
@ahejlsberg and @mhegazy can you take a look at this? |
| Union = 1 << 19, // Union (T | U) | ||
| Intersection = 1 << 20, // Intersection (T & U) | ||
| Anonymous = 1 << 21, // Anonymous | ||
| Instantiated = 1 << 22, // Instantiated anonymous type |
There was a problem hiding this comment.
I would preserve this flag unless you really need to free it up. In generic code we create lots of instantiated anonymous types and it would be nice not to incur the overhead of another property.
There was a problem hiding this comment.
I only need one flag right now (Spread), but I'll need another for Rest and Ryan will need one for Subset. Maybe ObjectLiteral is a better target?
FreshLiteral seems pretty easy to excise as well, but there are a lot of literals in any given program.
There was a problem hiding this comment.
Instantiated is back in. I'm looking at ObjectLiteral instead.
There was a problem hiding this comment.
I'd leave ObjectLiteral alone. Just free up the other two for now and then we can do more if and when it is needed. I'd prefer not incurring overhead unless we have to.
| if (hasComputedProperties) { | ||
| result.flags |= TypeFlags.ObjectLiteralPatternWithComputedProperties; | ||
| } | ||
| result.inObjectLiteralPatternWithComputedProperties = hasComputedProperties; |
There was a problem hiding this comment.
Only create this property if hasComputedProperties is true.
There was a problem hiding this comment.
Hm, turns out I was wrong when I thought that x.prop = undefined is a no-op. Fixed.
| * type itself. Note that the apparent type of a union type is the union type itself. | ||
| */ | ||
| function getApparentType(type: Type): Type { | ||
| function getApparentType(type: Type): ObjectType { |
There was a problem hiding this comment.
Why this change? This function isn't guaranteed to return an ObjectType.
There was a problem hiding this comment.
All the branches do return ObjectType, but I forgot about the else branch. Reverted.
|
|
||
| function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { | ||
| if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && maybeTypeOfKind(target, TypeFlags.ObjectType)) { | ||
| if (maybeTypeOfKind(target, TypeFlags.ObjectType) && !(target as ObjectType).inObjectLiteralPatternWithComputedProperties) { |
There was a problem hiding this comment.
The maybeTypeOfKind function could return true when target is a union or intersection containing an object type, so the second check needs to first ensure target is actually an object type.
There was a problem hiding this comment.
I was relying on unions and intersections not having inObjectLiteralPatternWithComputedProperties and having the check come back with undefined. Adding the check is the right thing, though.
| // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily | ||
| // be "pushed" onto a node using the contextualType property. | ||
| function getApparentTypeOfContextualType(node: Expression): Type { | ||
| function getApparentTypeOfContextualType(node: Expression): ObjectType { |
There was a problem hiding this comment.
The returned type could be something other than an ObjectType so this change isn't correct.
| const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral; | ||
| result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0); | ||
| result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); | ||
| result.inObjectLiteralPatternWithComputedProperties = patternWithComputedProperties; |
There was a problem hiding this comment.
Only set the property if patternWithComputedProperties is true.
|
I put |
|
Oops, I didn't see your new comments, @ahejlsberg. I put |
|
Why didn't you just introduce a new |
| } | ||
| if (hasComputedProperties) { | ||
| result.flags |= TypeFlags.ObjectLiteralPatternWithComputedProperties; | ||
| result.inObjectLiteralPatternWithComputedProperties = hasComputedProperties; |
There was a problem hiding this comment.
Also, shouldn't it be isObjectBlaBlaBla...? In other words, "is" instead of "in".
| (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); | ||
| let typeFlags: TypeFlags = 0; | ||
| let patternWithComputedProperties = false; | ||
| let patternWithComputedProperties: boolean | undefined; |
| function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): ResolvedType { | ||
| const members = createMap<Symbol>(); | ||
| let hasComputedProperties = false; | ||
| let hasComputedProperties: boolean; |
|
|
||
| // Return the type implied by an object binding pattern | ||
| function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { | ||
| function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): ResolvedType { |
There was a problem hiding this comment.
One more change that isn't necessary.
This is needed for object spread and rest, which will each need a type
flag.
There are 4-5 other likely targets for removal, and I may remove those
later.