Skip to content

Commit

Permalink
[NTI] Add inferred type to undeclared constructor properties.
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=154350174
  • Loading branch information
dimvar authored and Tyler Breisacher committed Apr 28, 2017
1 parent 6a41621 commit bfb95b8
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 16 deletions.
10 changes: 9 additions & 1 deletion src/com/google/javascript/jscomp/GlobalTypeInfo.java
Expand Up @@ -1830,7 +1830,15 @@ private void visitConstructorPropertyDeclaration(Node getProp) {
getProp.putBooleanProp(Node.CONSTANT_PROPERTY_DEF, true);
}
} else {
classType.addUndeclaredCtorProperty(pname, getProp);
JSType inferredType = null;
Node initializer = NodeUtil.getRValueOfLValue(getProp);
if (initializer != null) {
inferredType = simpleInferExprType(initializer);
}
if (inferredType == null) {
inferredType = commonTypes.UNKNOWN;
}
classType.addUndeclaredCtorProperty(pname, getProp, inferredType);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/com/google/javascript/jscomp/newtypes/Namespace.java
Expand Up @@ -187,8 +187,7 @@ public final void addProperty(
public final void addUndeclaredProperty(
String pname, Node defSite, JSType t, boolean isConstant) {
Preconditions.checkState(this.namespaceType == null);
if (otherProps.containsKey(pname)
&& !otherProps.get(pname).getType().isUnknown()) {
if (otherProps.containsKey(pname) && otherProps.get(pname).isDeclared()) {
return;
}
otherProps = otherProps.with(pname, isConstant
Expand Down
28 changes: 16 additions & 12 deletions src/com/google/javascript/jscomp/newtypes/RawNominalType.java
Expand Up @@ -585,16 +585,16 @@ public void addProtoProperty(String pname, Node defSite, JSType type, boolean is
public void addUndeclaredProtoProperty(String pname, Node defSite, JSType inferredType) {
Preconditions.checkState(!this.isFrozen);
Property existingProp = this.protoProps.get(pname);
if (existingProp == null || !existingProp.isDeclared()) {
JSType oldType = existingProp == null ? null : existingProp.getType();
if (oldType != null) {
inferredType = JSType.join(oldType, inferredType);
}
this.protoProps = this.protoProps.with(pname,
Property.makeWithDefsite(defSite, inferredType, null));
if (this.randomProps.containsKey(pname)) {
this.randomProps = this.randomProps.without(pname);
}
if (existingProp != null && existingProp.isDeclared()) {
return;
}
if (existingProp != null) {
inferredType = JSType.join(existingProp.getType(), inferredType);
}
this.protoProps =
this.protoProps.with(pname, Property.makeWithDefsite(defSite, inferredType, null));
if (this.randomProps.containsKey(pname)) {
this.randomProps = this.randomProps.without(pname);
}
}

Expand All @@ -611,9 +611,13 @@ public void addCtorProperty(String pname, Node defSite, JSType type, boolean isC
}

/** Add a new undeclared property to this class's constructor */
public void addUndeclaredCtorProperty(String pname, Node defSite) {
public void addUndeclaredCtorProperty(String pname, Node defSite, JSType inferredType) {
Preconditions.checkState(!this.isFrozen);
super.addUndeclaredProperty(pname, defSite, this.commonTypes.UNKNOWN, false);
Property existingProp = getNsProp(pname);
if (existingProp != null && !existingProp.isDeclared()) {
inferredType = JSType.join(existingProp.getType(), inferredType);
}
super.addUndeclaredProperty(pname, defSite, inferredType, false);
}

public JSType getCtorPropDeclaredType(String pname) {
Expand Down
39 changes: 38 additions & 1 deletion test/com/google/javascript/jscomp/NewTypeInferenceTest.java
Expand Up @@ -19926,7 +19926,7 @@ public void testAllowConstructorWithReturnToBeTypedAsFunction() {
"f(Foo);"));
}

public void testInstantiateTypeVariablesToUnknownWhenUsingCallApply() {
public void testHandleClassGenericsWhenUsingCallApply() {
typeCheck(LINE_JOINER.join(
"/**",
" * @constructor",
Expand Down Expand Up @@ -19992,4 +19992,41 @@ public void testInstantiateTypeVariablesToUnknownWhenUsingCallApply() {
"var /** number */ n = Foo.prototype.f.call(new Foo, 'asdf');"),
NewTypeInference.MISTYPED_ASSIGN_RHS);
}

public void testInferTypeOfUndeclaredConstructorProperties() {
typeCheck(LINE_JOINER.join(
"/** @constructor */",
"function Foo() {}",
"Foo.prop = 1;",
"function f() {",
" var /** string */ s = Foo.prop;",
"}"),
NewTypeInference.MISTYPED_ASSIGN_RHS);

typeCheck(LINE_JOINER.join(
"/** @constructor */",
"function Foo() {}",
"Foo.prop = 1;",
"Foo.prop = true;"));

// TODO(dimvar): we want to catch the warning here, which requires not tightening the
// property type. Will do in a follow-up CL.
typeCheck(LINE_JOINER.join(
"/** @constructor */",
"function Foo() {}",
"Foo.prop = 'asdf';",
"function f() {",
" var /** string */ s = Foo.prop;",
"}",
"Foo.prop = 1;"));

typeCheck(LINE_JOINER.join(
"/** @constructor */",
"function Foo() {}",
"Foo.prop = 'asdf';",
"function f() {",
" var /** string */ s = Foo.prop;",
"}",
"Foo.prop = globalVar;"));
}
}

0 comments on commit bfb95b8

Please sign in to comment.