Skip to content

Commit

Permalink
[NTI] Always allow casting to/from an interface type.
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=123038929
  • Loading branch information
dimvar authored and blickly committed May 24, 2016
1 parent c17287b commit 2324f2a
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 18 deletions.
8 changes: 6 additions & 2 deletions src/com/google/javascript/jscomp/NewTypeInference.java
Expand Up @@ -2101,8 +2101,12 @@ private EnvTypePair analyzeCastFwd(Node expr, TypeEnv inEnv) {
EnvTypePair pair = analyzeExprFwd(expr.getFirstChild(), inEnv);
JSType fromType = pair.type;
JSType toType = symbolTable.getCastType(expr);
if (!JSType.haveCommonSubtype(fromType, toType) && !fromType.hasTypeVariable()) {
warnings.add(JSError.make(expr, INVALID_CAST, fromType.toString(), toType.toString()));
if (!fromType.isInterfaceInstance()
&& !toType.isInterfaceInstance()
&& !JSType.haveCommonSubtype(fromType, toType)
&& !fromType.hasTypeVariable()) {
warnings.add(JSError.make(
expr, INVALID_CAST, fromType.toString(), toType.toString()));
}
pair.type = toType;
return pair;
Expand Down
5 changes: 5 additions & 0 deletions src/com/google/javascript/jscomp/newtypes/JSType.java
Expand Up @@ -1215,6 +1215,11 @@ public NominalType getNominalTypeIfSingletonObj() {
? Iterables.getOnlyElement(getObjs()).getNominalType() : null;
}

public boolean isInterfaceInstance() {
NominalType nt = getNominalTypeIfSingletonObj();
return nt != null && nt.isInterface();
}

// True for functions and instances of Object (including object literals).
public boolean isNonClassyObject() {
NominalType nt = getNominalTypeIfSingletonObj();
Expand Down
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/newtypes/NominalType.java
Expand Up @@ -510,6 +510,6 @@ public boolean equals(Object other) {
}
Preconditions.checkState(other instanceof NominalType);
NominalType o = (NominalType) other;
return Objects.equals(typeMap, o.typeMap) && this.rawType.equals(o.rawType);
return this.rawType.equals(o.rawType) && Objects.equals(typeMap, o.typeMap);
}
}
30 changes: 15 additions & 15 deletions src/com/google/javascript/jscomp/newtypes/RawNominalType.java
Expand Up @@ -58,7 +58,7 @@ public final class RawNominalType extends Namespace {
// have the same superclass and interfaces fields, because they have the
// same raw type. You need to instantiate these fields to get the correct
// type maps, eg, see NominalType#isSubtypeOf.
private NominalType superClass = null;
private NominalType superclass = null;
private ImmutableSet<NominalType> interfaces = null;
private final Kind kind;
// Used in GlobalTypeInfo to find type mismatches in the inheritance chain.
Expand Down Expand Up @@ -209,21 +209,21 @@ boolean hasAncestorClass(RawNominalType ancestor) {
Preconditions.checkState(ancestor.isClass());
if (this == ancestor) {
return true;
} else if (this.superClass == null) {
} else if (this.superclass == null) {
return false;
} else {
return this.superClass.hasAncestorClass(ancestor);
return this.superclass.hasAncestorClass(ancestor);
}
}

/** @return Whether the superclass can be added without creating a cycle. */
public boolean addSuperClass(NominalType superClass) {
public boolean addSuperClass(NominalType superclass) {
Preconditions.checkState(!this.isFinalized);
Preconditions.checkState(this.superClass == null);
if (superClass.hasAncestorClass(this)) {
Preconditions.checkState(this.superclass == null);
if (superclass.hasAncestorClass(this)) {
return false;
}
this.superClass = superClass;
this.superclass = superclass;
return true;
}

Expand Down Expand Up @@ -283,7 +283,7 @@ public boolean addInterfaces(ImmutableSet<NominalType> interfaces) {
}

public NominalType getSuperClass() {
return superClass;
return this.superclass;
}

public ImmutableSet<NominalType> getInterfaces() {
Expand Down Expand Up @@ -326,8 +326,8 @@ private Property getPropFromClass(String pname) {
if (p != null) {
return p;
}
if (superClass != null) {
p = superClass.getProp(pname);
if (this.superclass != null) {
p = this.superclass.getProp(pname);
if (p != null) {
return p;
}
Expand Down Expand Up @@ -371,8 +371,8 @@ public JSType getInstancePropDeclaredType(String pname) {
Property p = getProp(pname);
if (p == null) {
return null;
} else if (p.getDeclaredType() == null && superClass != null) {
return superClass.getPropDeclaredType(pname);
} else if (p.getDeclaredType() == null && this.superclass != null) {
return this.superclass.getPropDeclaredType(pname);
}
return p.getDeclaredType();
}
Expand Down Expand Up @@ -412,8 +412,8 @@ ImmutableSet<String> getAllPropsOfClass() {
Preconditions.checkState(this.isFinalized);
if (this.allProps == null) {
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
if (superClass != null) {
builder.addAll(superClass.getAllPropsOfClass());
if (this.superclass != null) {
builder.addAll(this.superclass.getAllPropsOfClass());
}
this.allProps = builder.addAll(classProps.keySet())
.addAll(protoProps.keySet()).build();
Expand Down Expand Up @@ -548,7 +548,7 @@ public void finalize() {
}
}
JSType protoObject = JSType.fromObjectType(ObjectType.makeObjectType(
this.superClass, this.protoProps,
this.superclass, this.protoProps,
null, null, false, ObjectKind.UNRESTRICTED));
addCtorProperty("prototype", null, protoObject, false);
this.isFinalized = true;
Expand Down
Expand Up @@ -16725,4 +16725,33 @@ public void testSpecializeAfterPropertyTest() {
"}"),
NewTypeInference.MISTYPED_ASSIGN_RHS);
}

public void testAllowCastingToFromInterface() {
typeCheck(LINE_JOINER.join(
"/** @constructor */",
"function Foo() {}",
"/** @interface */",
"function Bar() {}",
"function f(/** !Foo */ x) {",
" return /** @type {!Bar} */ (x);",
"}"));

typeCheck(LINE_JOINER.join(
"/** @interface */",
"function Foo() {}",
"/** @constructor */",
"function Bar() {}",
"function f(/** !Foo */ x) {",
" return /** @type {!Bar} */ (x);",
"}"));

typeCheck(LINE_JOINER.join(
"/** @interface */",
"function Foo() {}",
"/** @interface */",
"function Bar() {}",
"function f(/** !Foo */ x) {",
" return /** @type {!Bar} */ (x);",
"}"));
}
}

0 comments on commit 2324f2a

Please sign in to comment.