From c20dc57762efb2fb980e0672133a61ee3951bd74 Mon Sep 17 00:00:00 2001 From: dimvar Date: Thu, 22 Jun 2017 14:10:45 -0700 Subject: [PATCH] Instantiate to ? when joining with empty typemap, to avoid somewhat dubious warnings. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159874119 --- .../jscomp/newtypes/NominalType.java | 14 ++++++----- .../jscomp/NewTypeInferenceTest.java | 23 ++++++++++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/com/google/javascript/jscomp/newtypes/NominalType.java b/src/com/google/javascript/jscomp/newtypes/NominalType.java index 777e28324ae..f329676b4f9 100644 --- a/src/com/google/javascript/jscomp/newtypes/NominalType.java +++ b/src/com/google/javascript/jscomp/newtypes/NominalType.java @@ -580,7 +580,7 @@ private boolean instantiationIsUnknownOrIdentity() { return true; } - private static ImmutableMap joinTypeMaps(NominalType nt1, NominalType nt2) { + private static NominalType joinTypeMaps(NominalType nt1, NominalType nt2) { checkState(nt1.rawType.equals(nt2.rawType)); ImmutableMap.Builder builder = ImmutableMap.builder(); if (nt1.isIObject()) { @@ -589,18 +589,20 @@ private static ImmutableMap joinTypeMaps(NominalType nt1, Nomina builder.put(indexTypevar, JSType.meet(nt1.getIndexType(), nt2.getIndexType())); String indexedTypevar = nt1.rawType.getTypeParameters().get(1); builder.put(indexedTypevar, JSType.join(nt1.getIndexedType(), nt2.getIndexedType())); - return builder.build(); + return new NominalType(builder.build(), nt1.rawType); } if (nt1.typeMap.isEmpty() || nt2.typeMap.isEmpty()) { - return ImmutableMap.of(); + return nt1.instantiateGenericsWithUnknown(); } for (String typevar : nt1.typeMap.keySet()) { builder.put(typevar, JSType.join(nt1.typeMap.get(typevar), nt2.typeMap.get(typevar))); } - return builder.build(); + return new NominalType(builder.build(), nt1.rawType); } - // A special-case of join. + /** + * A special-case of join. If either argument is null, it returns null. + */ static NominalType join(NominalType c1, NominalType c2) { if (c1 == null || c2 == null) { return null; @@ -612,7 +614,7 @@ static NominalType join(NominalType c1, NominalType c2) { return c1; } if (c1.rawType.equals(c2.rawType)) { - return c1.isGeneric() ? new NominalType(joinTypeMaps(c1, c2), c1.rawType) : c1; + return c1.isGeneric() ? joinTypeMaps(c1, c2) : c1; } // If c1.isRawSubtypeOf(c2) but not c1.isNominalSubtypeOf(c2), we would want to change // joinTypeMaps to handle type maps with different domains. Basically, we want to go up diff --git a/test/com/google/javascript/jscomp/NewTypeInferenceTest.java b/test/com/google/javascript/jscomp/NewTypeInferenceTest.java index eac3fcc516c..677d317cde3 100644 --- a/test/com/google/javascript/jscomp/NewTypeInferenceTest.java +++ b/test/com/google/javascript/jscomp/NewTypeInferenceTest.java @@ -19396,7 +19396,7 @@ public void testDontCrashWhenUnifyingNominalTypeWithEmptyTypemap() { "};")); } - public void testDontCrashWhenJoiningNominalTypeWithEmptyTypemap() { + public void testJoiningNominalTypeWithEmptyTypemap() { typeCheck(LINE_JOINER.join( "/**", " * @constructor", @@ -19406,6 +19406,27 @@ public void testDontCrashWhenJoiningNominalTypeWithEmptyTypemap() { "Foo.prototype.conditional = function() {", " return true ? /** @type {Foo} */ (new Foo) : this;", "};")); + + typeCheck(LINE_JOINER.join( + "/**", + " * @constructor", + " * @template T", + " */", + "var Foo = function() {};", + "Foo.prototype.conditional = function() {", + " var /** !Foo */ n = true ? /** @type {!Foo} */ (new Foo) : this;", + "};")); + + // The result of the join is Foo + typeCheck(LINE_JOINER.join( + "/**", + " * @constructor", + " * @template T", + " */", + "var Foo = function() {};", + "Foo.prototype.conditional = function() {", + " var /** !Foo */ n = true ? /** @type {!Foo} */ (new Foo) : this;", + "};")); } public void testSpecializeFunctionReturnType() {