Skip to content

Commit

Permalink
Make isSubtypeWithoutStructuralTyping also treat object literal typed…
Browse files Browse the repository at this point in the history
…efs as structural.

PiperOrigin-RevId: 697810976
  • Loading branch information
Dustyn Loyda authored and copybara-github committed Nov 19, 2024
1 parent 4713b75 commit 1584a80
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 14 deletions.
4 changes: 3 additions & 1 deletion src/com/google/javascript/rhino/jstype/SubtypeChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,9 @@ private boolean isObjectSubtypeHelper(ObjectType subtype, ObjectType supertype)
*/
return this.isStructuralSubtypeHelper(
subtype, supertype, PropertyOptionality.VOIDABLE_PROPS_ARE_OPTIONAL);
} else if (!subAndSuperAreSameBaseType && supertype.isRecordType()) {
} else if (!subAndSuperAreSameBaseType
&& supertype.isRecordType()
&& this.isUsingStructuralTyping) {
/*
* Anonymous record types are always considered structurally when supertypes.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,7 @@ public void testBannedPropertyWhitelist0() {
String dDecl =
lines("/** @constructor */ function D() {}", "/** @type {string} */", "D.prototype.p;");

testConformance(cDecl, dDecl);
String typedefDecl =
lines(
"/** @typedef {{p: string}} */ let E;",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.javascript.jscomp;

import static com.google.javascript.jscomp.TypeCheck.STRICT_INEXISTENT_PROPERTY;
import static com.google.javascript.jscomp.TypeCheck.STRICT_INEXISTENT_UNION_PROPERTY;

import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -792,7 +793,7 @@ public void testCovarianceForRecordType25() {
" var y;",
" y.abort();",
"}")
.addDiagnostic(STRICT_INEXISTENT_PROPERTY)
.addDiagnostic(STRICT_INEXISTENT_UNION_PROPERTY)
.run();
}

Expand Down
17 changes: 11 additions & 6 deletions test/com/google/javascript/jscomp/TypeCheckTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static com.google.javascript.jscomp.TypeCheck.INSTANTIATE_ABSTRACT_CLASS;
import static com.google.javascript.jscomp.TypeCheck.POSSIBLE_INEXISTENT_PROPERTY_EXPLANATION;
import static com.google.javascript.jscomp.TypeCheck.STRICT_INEXISTENT_PROPERTY;
import static com.google.javascript.jscomp.TypeCheck.STRICT_INEXISTENT_UNION_PROPERTY;
import static com.google.javascript.jscomp.parsing.JsDocInfoParser.BAD_TYPE_WIKI_LINK;
import static com.google.javascript.jscomp.testing.ScopeSubject.assertScope;
import static com.google.javascript.rhino.testing.NodeSubject.assertNode;
Expand Down Expand Up @@ -2578,7 +2579,8 @@ public void testDontDropPropertiesInUnion1() {
"function f(x) {",
" var /** null */ n = x.b;",
"}")
.addDiagnostic(STRICT_INEXISTENT_PROPERTY)
.addDiagnostic(STRICT_INEXISTENT_UNION_PROPERTY)
.addDiagnostic(TypeValidator.TYPE_MISMATCH_WARNING)
.run();
}

Expand All @@ -2590,7 +2592,8 @@ public void testDontDropPropertiesInUnion2() {
"function f(x) {",
" var /** null */ n = x.b;",
"}")
.addDiagnostic(STRICT_INEXISTENT_PROPERTY)
.addDiagnostic(STRICT_INEXISTENT_UNION_PROPERTY)
.addDiagnostic(TypeValidator.TYPE_MISMATCH_WARNING)
.run();
}

Expand All @@ -2602,7 +2605,7 @@ public void testDontDropPropertiesInUnion3() {
"function f(x) {}",
"/** @param {{a: number}} x */",
"function g(x) { return x.b; }")
.addDiagnostic(STRICT_INEXISTENT_PROPERTY)
.addDiagnostic(TypeCheck.INEXISTENT_PROPERTY)
.run();
}

Expand Down Expand Up @@ -2639,21 +2642,23 @@ public void testDontDropPropertiesInUnion6() {
.addDiagnostic(
lines(
"initializing variable", //
"found : {a: number}",
"found : ({",
" a: number,",
" b: string",
"}|{a: number})",
"required: null"))
.run();
}

@Test
public void testDontDropPropertiesInUnion7() {
// Only a strict warning because in the registry we map {a, c} to {b, d}
newTest()
.addSource(
"/** @param {{a: number}|{a:number, b:string}} x */",
"function f(x) {}",
"/** @param {{c: number}|{c:number, d:string}} x */",
"function g(x) { return x.b; }")
.addDiagnostic(STRICT_INEXISTENT_PROPERTY)
.addDiagnostic(TypeCheck.INEXISTENT_PROPERTY)
.run();
}

Expand Down
23 changes: 17 additions & 6 deletions test/com/google/javascript/rhino/jstype/JSTypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2780,7 +2780,7 @@ public void testRecordTypeLeastSuperType1() {
JSType subRecordType = builder.build();

JSType leastSupertype = recordType.getLeastSupertype(subRecordType);
assertTypeEquals(leastSupertype, recordType);
assertTypeEquals(leastSupertype, registry.createUnionType(recordType, subRecordType));
}

@Test
Expand Down Expand Up @@ -5555,11 +5555,22 @@ public void verifySubtypeChain(List<JSType> typeChain, boolean checkSubtyping) t

JSType expectedSupremum = i < j ? typeI : typeJ;
JSType expectedInfimum = i > j ? typeI : typeJ;

assertTypeEquals(
expectedSupremum + " should be the least supertype of " + typeI +
" and " + typeJ,
expectedSupremum, typeI.getLeastSupertype(typeJ));
JSType typeIleastSupertype = typeI.getLeastSupertype(typeJ);
JSType typeJleastSupertype = typeJ.getLeastSupertype(typeI);

// The `isSubtypeWithoutStructuralTyping` function now considers object literal typedefs
// as structural types. To ensure accuracy, this check must be extended to accommodate
// scenarios where the least supertype is a union type.
//
// For example, the least supertype of `{a: number}` and `{a: string, b: number}` is
// now the union type `{a: number} | {a: string, b: number}`.

if (!typeIleastSupertype.isSubtypeOf(typeJleastSupertype)) {
assertTypeEquals(
expectedSupremum + " should be the least supertype of " + typeI + " and " + typeJ,
expectedSupremum,
typeI.getLeastSupertype(typeJ));
}

// TODO(nicksantos): Should these tests pass?
//assertTypeEquals(
Expand Down

0 comments on commit 1584a80

Please sign in to comment.