Skip to content

Commit

Permalink
Add extra information to help understand type mismatch errors for rec…
Browse files Browse the repository at this point in the history
…ord types.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=157844020
  • Loading branch information
mrolig5267319 authored and brad4d committed Jun 5, 2017
1 parent b37e600 commit f641b9a
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 61 deletions.
69 changes: 60 additions & 9 deletions src/com/google/javascript/jscomp/TypeValidator.java
Expand Up @@ -28,6 +28,7 @@
import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.VOID_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.VOID_TYPE;


import com.google.common.base.Joiner;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.javascript.jscomp.parsing.parser.util.format.SimpleFormat; import com.google.javascript.jscomp.parsing.parser.util.format.SimpleFormat;
import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.JSDocInfo;
Expand All @@ -48,6 +49,8 @@
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.Nullable; import javax.annotation.Nullable;


/** /**
Expand Down Expand Up @@ -83,6 +86,13 @@ class TypeValidator implements Serializable {
"found : {1}\n" + "found : {1}\n" +
"required: {2}"; "required: {2}";


private static final String FOUND_REQUIRED_MISSING =
"{0}\n"
+ "found : {1}\n"
+ "required: {2}\n"
+ "missing : [{3}]\n"
+ "mismatch: [{4}]";

static final DiagnosticType INVALID_CAST = static final DiagnosticType INVALID_CAST =
DiagnosticType.warning("JSC_INVALID_CAST", DiagnosticType.warning("JSC_INVALID_CAST",
"invalid cast - must be a subtype or supertype\n" + "invalid cast - must be a subtype or supertype\n" +
Expand Down Expand Up @@ -777,7 +787,7 @@ void expectAbstractMethodsImplemented(Node n, FunctionType ctorType) {
} }


/** Report a type mismatch */ /** Report a type mismatch */
private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSType required) { private void mismatch(NodeTraversal unusedT, Node n, String msg, JSType found, JSType required) {
mismatch(n, msg, found, required); mismatch(n, msg, found, required);
} }


Expand All @@ -787,26 +797,67 @@ private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSTypeN


private void mismatch(Node n, String msg, JSType found, JSType required) { private void mismatch(Node n, String msg, JSType found, JSType required) {
if (!found.isSubtype(required, this.subtypingMode)) { if (!found.isSubtype(required, this.subtypingMode)) {
JSError err = JSError.make( Set<String> missing = null;
n, TYPE_MISMATCH_WARNING, formatFoundRequired(msg, found, required)); Set<String> mismatch = null;
if (required.isStructuralType()) {
missing = new TreeSet<>();
mismatch = new TreeSet<>();
ObjectType requiredObject = required.toMaybeObjectType();
ObjectType foundObject = found.toMaybeObjectType();
if (requiredObject != null && foundObject != null) {
for (String property : requiredObject.getPropertyNames()) {
JSType propRequired = requiredObject.getPropertyType(property);
boolean hasProperty = foundObject.hasProperty(property);
if (!propRequired.isExplicitlyVoidable() || hasProperty) {
if (hasProperty) {
if (!foundObject.getPropertyType(property).isSubtype(propRequired, subtypingMode)) {
mismatch.add(property);
}
} else {
missing.add(property);
}
}
}
}
}
JSError err =
JSError.make(
n,
TYPE_MISMATCH_WARNING,
formatFoundRequired(msg, found, required, missing, mismatch));
TypeMismatch.registerMismatch( TypeMismatch.registerMismatch(
this.mismatches, this.implicitInterfaceUses, found, required, err); this.mismatches, this.implicitInterfaceUses, found, required, err);
report(err); report(err);
} }
} }


/** /** Formats a found/required error message. */
* Formats a found/required error message. private static String formatFoundRequired(
*/ String description,
private static String formatFoundRequired(String description, JSType found, JSType found,
JSType required) { JSType required,
Set<String> missing,
Set<String> mismatch) {
String foundStr = found.toString(); String foundStr = found.toString();
String requiredStr = required.toString(); String requiredStr = required.toString();
if (foundStr.equals(requiredStr)) { if (foundStr.equals(requiredStr)) {
foundStr = found.toAnnotationString(); foundStr = found.toAnnotationString();
requiredStr = required.toAnnotationString(); requiredStr = required.toAnnotationString();
} }
return MessageFormat.format(FOUND_REQUIRED, description, foundStr, requiredStr); String missingStr = "";
String mismatchStr = "";
if (missing != null && !missing.isEmpty()) {
missingStr = Joiner.on(",").join(missing);
}
if (mismatch != null && !mismatch.isEmpty()) {
mismatchStr = Joiner.on(",").join(mismatch);
}
if (missingStr.length() > 0 || mismatchStr.length() > 0) {
return MessageFormat.format(
FOUND_REQUIRED_MISSING, description, foundStr, requiredStr, missingStr, mismatchStr);
} else {
return MessageFormat.format(FOUND_REQUIRED, description, foundStr, requiredStr);
}
} }


/** /**
Expand Down

0 comments on commit f641b9a

Please sign in to comment.