Skip to content

Commit

Permalink
[NTI] Handle function declarations on namespaces when there is no fun…
Browse files Browse the repository at this point in the history
…ction literal.

DeclaredGlobalExternsOnWindow generates such definitions.

Fixes #2167 on github.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=142707692
  • Loading branch information
dimvar authored and blickly committed Dec 22, 2016
1 parent 5165243 commit e5b4bc6
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 8 deletions.
19 changes: 12 additions & 7 deletions src/com/google/javascript/jscomp/GlobalTypeInfo.java
Expand Up @@ -1603,15 +1603,21 @@ private NTIScope visitFunctionLate(Node fn, RawNominalType ownerType) {
// Used when declaring constructor and namespace properties. Prototype property // Used when declaring constructor and namespace properties. Prototype property
// declarations are similar, but different enough that they didn't neatly fit // declarations are similar, but different enough that they didn't neatly fit
// in this method (eg, redeclaration warnings are stricter). // in this method (eg, redeclaration warnings are stricter).
PropertyType getPropTypeHelper( PropertyType getPropTypeHelper(JSDocInfo jsdoc, Node declNode, RawNominalType thisType) {
JSDocInfo jsdoc, Node initializer, RawNominalType thisType) { Node initializer = NodeUtil.getRValueOfLValue(declNode);
PropertyType result = new PropertyType(); PropertyType result = new PropertyType();
DeclaredFunctionType dft = null; DeclaredFunctionType dft = null;
if (initializer != null && initializer.isFunction()) { if (initializer != null && initializer.isFunction()) {
dft = visitFunctionLate(initializer, thisType).getDeclaredFunctionType(); dft = visitFunctionLate(initializer, thisType).getDeclaredFunctionType();
} }
if (jsdoc != null && jsdoc.hasType()) { if (jsdoc != null && jsdoc.hasType()) {
result.declType = getDeclaredTypeOfNode(jsdoc, currentScope); result.declType = getDeclaredTypeOfNode(jsdoc, currentScope);
} else if (initializer == null && jsdoc != null && jsdoc.containsFunctionDeclaration()) {
// We're parsing a function declaration without a function initializer
Preconditions.checkState(declNode.isGetProp() && declNode.getParent().isExprResult());
dft = computeFnDeclaredType(
jsdoc, declNode.getLastChild().getString(), declNode, null, currentScope);
result.declType = commonTypes.fromFunctionType(dft.toFunctionType());
} else if (initializer != null && initializer.isFunction()) { } else if (initializer != null && initializer.isFunction()) {
JSType funType = commonTypes.fromFunctionType(dft.toFunctionType()); JSType funType = commonTypes.fromFunctionType(dft.toFunctionType());
if ((jsdoc != null && jsdoc.containsFunctionDeclaration()) if ((jsdoc != null && jsdoc.containsFunctionDeclaration())
Expand Down Expand Up @@ -1780,8 +1786,7 @@ private void visitNamespacePropertyDeclaration(


Namespace ns = currentScope.getNamespace(QualifiedName.fromNode(recv)); Namespace ns = currentScope.getNamespace(QualifiedName.fromNode(recv));
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(declNode); JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(declNode);
Node initializer = NodeUtil.getRValueOfLValue(declNode); PropertyType pt = getPropTypeHelper(jsdoc, declNode, null);
PropertyType pt = getPropTypeHelper(jsdoc, initializer, null);
JSType propDeclType = pt.declType; JSType propDeclType = pt.declType;
JSType propInferredFunType = pt.inferredFunType; JSType propInferredFunType = pt.inferredFunType;
boolean isConst = isConst(declNode); boolean isConst = isConst(declNode);
Expand All @@ -1808,8 +1813,8 @@ private void visitNamespacePropertyDeclaration(
ns.addUndeclaredProperty(pname, declNode, propInferredFunType, false); ns.addUndeclaredProperty(pname, declNode, propInferredFunType, false);
} else { } else {
// Try to infer the prop type, but don't say that the prop is declared. // Try to infer the prop type, but don't say that the prop is declared.
JSType t = initializer == null Node initializer = NodeUtil.getRValueOfLValue(declNode);
? null : simpleInferExprType(initializer); JSType t = initializer == null ? null : simpleInferExprType(initializer);
if (t == null) { if (t == null) {
t = commonTypes.UNKNOWN; t = commonTypes.UNKNOWN;
} }
Expand All @@ -1833,7 +1838,7 @@ private void visitClassPropertyDeclaration(Node getProp) {
RawNominalType rawType = thisType.getRawNominalType(); RawNominalType rawType = thisType.getRawNominalType();
String pname = getProp.getLastChild().getString(); String pname = getProp.getLastChild().getString();
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(getProp); JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(getProp);
PropertyType pt = getPropTypeHelper(jsdoc, initializer, rawType); PropertyType pt = getPropTypeHelper(jsdoc, getProp, rawType);
JSType propDeclType = pt.declType; JSType propDeclType = pt.declType;
JSType propInferredFunType = pt.inferredFunType; JSType propInferredFunType = pt.inferredFunType;
boolean isConst = isConst(getProp); boolean isConst = isConst(getProp);
Expand Down
14 changes: 14 additions & 0 deletions test/com/google/javascript/jscomp/NewTypeInferenceTest.java
Expand Up @@ -18473,4 +18473,18 @@ public void testDontRemoveLooseObjects() {
" }", " }",
"}")); "}"));
} }

public void testFunctionDeclsWithoutFunctionLiteralOnNamespaces() {
typeCheck(
"window.setTimeout(123);",
NewTypeInference.INVALID_ARGUMENT_TYPE);

typeCheckCustomExterns(
DEFAULT_EXTERNS + LINE_JOINER.join(
"/** @const */ var ns = {};",
"/** @param {number} x */",
"ns.foobar;"),
"ns.foobar('asdf');",
NewTypeInference.INVALID_ARGUMENT_TYPE);
}
} }
Expand Up @@ -158,7 +158,13 @@ public abstract class NewTypeInferenceTestBase extends CompilerTypeTestCase {
"Window.prototype.closed;", "Window.prototype.closed;",
"/** @type {!Window} */", "/** @type {!Window} */",
"var window;", "var window;",
"", "/**",
" * @param {Function|string} callback",
" * @param {number=} opt_delay",
" * @param {...*} var_args",
" * @return {number}",
" */",
"function setTimeout(callback, opt_delay, var_args) {}",
"/**", "/**",
" * @constructor", " * @constructor",
" * @extends {Array<string>}", " * @extends {Array<string>}",
Expand Down

0 comments on commit e5b4bc6

Please sign in to comment.