Skip to content

Commit 44665ec

Browse files
brandjoncopybara-github
authored andcommitted
Properly gate dynamic type checking with flag
Previously f60a22e replaced `--experimental_starlark_types` with two separate flags, `--experimental_starlark_type_syntax` and `--experimental_starlark_type_checking`. However, it failed to wire the latter through to the actual type checking logic. This makes it impossible to process bzl files that contain type annotations without also attempting to check those types -- a no-no for Bazel 9.0, which should tolerate but ignore type annotations. - Clarify type checking flag's description. - Moved key constant for type checking flag from `BuildLanguageOptions` into `StarlarkSemantics`, since it is referenced within the Starlark interpreter itself. - Rename `FileOptions#allowArbitraryTypeExpressions` -> `tolerateInvalidTypeExpressions` to make the intent clearer to the reader. - Guard on flag in `Eval.java` and `StarlarkFunction.java`. - Rename `TypeCheckTest` -> `DynamicTypeCheckTest` in anticipation of upcoming static type checking. Fixes #27716. PiperOrigin-RevId: 839269449 Change-Id: Ieb01c00a30758d7d486ef5ffdb03198fcff233ac
1 parent 413f554 commit 44665ec

File tree

12 files changed

+56
-28
lines changed

12 files changed

+56
-28
lines changed

src/main/java/com/google/devtools/build/lib/packages/semantics/BuildLanguageOptions.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,8 @@ public final class BuildLanguageOptions extends OptionsBase {
700700
metadataTags = {OptionMetadataTag.EXPERIMENTAL},
701701
help =
702702
"Enables type checking in files and functions that contain type annotations or related "
703-
+ "syntax.")
703+
+ "syntax. (When this flag is disabled, Bazel is more forgiving of invalid types in "
704+
+ "type annotations.)")
704705
public boolean experimentalStarlarkTypeChecking;
705706

706707
// TODO: b/350661266 - Delete this flag.
@@ -950,7 +951,9 @@ private void setFlags(FlagConsumer consumer) {
950951
.setBool(EXPERIMENTAL_RULE_EXTENSION_API, experimentalRuleExtensionApi)
951952
.setBool(EXPERIMENTAL_DORMANT_DEPS, experimentalDormantDeps)
952953
.setBool(EXPERIMENTAL_STARLARK_TYPE_SYNTAX, experimentalStarlarkTypeSyntax)
953-
.setBool(EXPERIMENTAL_STARLARK_TYPE_CHECKING, experimentalStarlarkTypeChecking)
954+
.setBool(
955+
StarlarkSemantics.EXPERIMENTAL_STARLARK_TYPE_CHECKING,
956+
experimentalStarlarkTypeChecking)
954957
.set(EXPERIMENTAL_STARLARK_TYPES_ALLOWED_PATHS, experimentalStarlarkTypesAllowedPaths)
955958
.setBool(INCOMPATIBLE_ENABLE_DEPRECATED_LABEL_APIS, enableDeprecatedLabelApis)
956959
.setBool(
@@ -1126,8 +1129,6 @@ public FlagConsumer setBool(String key, boolean ignored) {
11261129

11271130
public static final String EXPERIMENTAL_STARLARK_TYPE_SYNTAX =
11281131
FlagConstants.EXPERIMENTAL_STARLARK_TYPE_SYNTAX_FLAG_NAME;
1129-
public static final String EXPERIMENTAL_STARLARK_TYPE_CHECKING =
1130-
"-experimental_starlark_type_checking";
11311132
public static final String INCOMPATIBLE_ENABLE_DEPRECATED_LABEL_APIS =
11321133
"+incompatible_enable_deprecated_label_apis";
11331134
public static final String INCOMPATIBLE_STOP_EXPORTING_BUILD_FILE_PATH =

src/main/java/com/google/devtools/build/lib/skyframe/BzlCompileFunction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ static BzlCompileValue computeInline(
212212
.allowTypeSyntax(
213213
semantics.getBool(BuildLanguageOptions.EXPERIMENTAL_STARLARK_TYPE_SYNTAX)
214214
&& typeSyntaxAllowlistMatchesPath)
215-
.allowArbitraryTypeExpressions(
216-
!semantics.getBool(BuildLanguageOptions.EXPERIMENTAL_STARLARK_TYPE_CHECKING))
215+
.tolerateInvalidTypeExpressions(
216+
!semantics.getBool(StarlarkSemantics.EXPERIMENTAL_STARLARK_TYPE_CHECKING))
217217
.build();
218218
StarlarkFile file = StarlarkFile.parse(input, options);
219219

src/main/java/net/starlark/java/eval/Eval.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ private static StarlarkFunction newFunction(StarlarkThread.Frame fr, Resolver.Fu
171171
int nparams =
172172
rfn.getParameters().size() - (rfn.hasKwargs() ? 1 : 0) - (rfn.hasVarargs() ? 1 : 0);
173173
@Nullable CallableType functionType = rfn.getFunctionType();
174+
boolean dynamicTypeCheckingEnabled =
175+
fr.thread.getSemantics().getBool(StarlarkSemantics.EXPERIMENTAL_STARLARK_TYPE_CHECKING);
174176
for (int i = 0; i < nparams; i++) {
175177
Expression expr = rfn.getParameters().get(i).getDefaultValue();
176178
if (expr == null && defaults == null) {
@@ -182,7 +184,7 @@ private static StarlarkFunction newFunction(StarlarkThread.Frame fr, Resolver.Fu
182184
Object defaultValue = expr == null ? StarlarkFunction.MANDATORY : eval(fr, expr);
183185
defaults[i - (nparams - defaults.length)] = defaultValue;
184186

185-
if (functionType != null) {
187+
if (dynamicTypeCheckingEnabled && functionType != null) {
186188
// Typecheck the default value
187189
StarlarkType parameterType = functionType.getParameterTypeByPos(i);
188190
if (!TypeChecker.isValueSubtypeOf(defaultValue, parameterType)) {

src/main/java/net/starlark/java/eval/StarlarkFunction.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -537,9 +537,14 @@ public Object call(StarlarkThread thread) throws EvalException, InterruptedExcep
537537
kwargs == null ? Dict.of(thread.mutability()) : Dict.wrap(thread.mutability(), kwargs);
538538
}
539539

540-
// Runtime type check
541-
StarlarkType type = owner.getStarlarkType();
542-
if (type instanceof Types.CallableType functionType) {
540+
Types.CallableType functionType =
541+
thread.getSemantics().getBool(StarlarkSemantics.EXPERIMENTAL_STARLARK_TYPE_CHECKING)
542+
&& owner.getStarlarkType() instanceof Types.CallableType
543+
? (Types.CallableType) owner.getStarlarkType()
544+
: null;
545+
546+
// Argument value dynamic type check, if enabled.
547+
if (functionType != null) {
543548
for (int i = 0; i < functionType.getParameterTypes().size(); i++) {
544549
if (locals[i] == null) {
545550
continue; // the default value is already type checked
@@ -572,8 +577,8 @@ public Object call(StarlarkThread thread) throws EvalException, InterruptedExcep
572577
fr.locals = locals;
573578
Object returnValue = Eval.execFunctionBody(fr, rfn.getBody());
574579

575-
// Return value check
576-
if (type instanceof Types.CallableType functionType) {
580+
// Return value dynamic type check, if enabled.
581+
if (functionType != null) {
577582
if (!TypeChecker.isValueSubtypeOf(returnValue, functionType.getReturnType())) {
578583
throw Starlark.errorf(
579584
"%s(): returns value of type '%s', declares '%s'",

src/main/java/net/starlark/java/eval/StarlarkSemantics.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ public final String toString() {
267267
public static final String INTERNAL_BAZEL_ONLY_UTF_8_BYTE_STRINGS =
268268
"-internal_bazel_only_utf_8_byte_strings";
269269

270+
/** Whether (static and/or dynamic) type checking should be performed. */
271+
// TODO: #27370 - Consider splitting this into separate options for static vs dynamic.
272+
public static final String EXPERIMENTAL_STARLARK_TYPE_CHECKING =
273+
"-experimental_starlark_type_checking";
274+
270275
/** Globally Override fail(stack_trace=) to true. Flag default is false. */
271276
public static final String FORCE_STARLARK_STACK_TRACE = "-force_starlark_stack_trace";
272277
}

src/main/java/net/starlark/java/syntax/FileOptions.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,16 @@ public abstract class FileOptions {
8282
public abstract boolean allowTypeSyntax();
8383

8484
/**
85-
* If true, type expressions may be any valid expression except for unparenthesized tuples.
86-
* Otherwise type expressions must represent a valid type.
85+
* If true, type expressions in annotations and {@code type} declarations may be any valid
86+
* expression (except for unparenthesized tuples, which are grammatically ambiguous). Otherwise
87+
* type expressions must represent a valid type.
8788
*
8889
* <p>Enabling this boolean is helpful for backwards compatibility, but results in an AST that is
8990
* not usable for type checking.
9091
*
9192
* <p>This has no effect if {@link #allowTypeSyntax} is false.
9293
*/
93-
public abstract boolean allowArbitraryTypeExpressions();
94+
public abstract boolean tolerateInvalidTypeExpressions();
9495

9596
public static Builder builder() {
9697
// These are the DEFAULT values.
@@ -101,7 +102,7 @@ public static Builder builder() {
101102
.requireLoadStatementsFirst(true)
102103
.stringLiteralsAreAsciiOnly(false)
103104
.allowTypeSyntax(false)
104-
.allowArbitraryTypeExpressions(false);
105+
.tolerateInvalidTypeExpressions(false);
105106
}
106107

107108
public abstract Builder toBuilder();
@@ -122,7 +123,7 @@ public abstract static class Builder {
122123

123124
public abstract Builder allowTypeSyntax(boolean value);
124125

125-
public abstract Builder allowArbitraryTypeExpressions(boolean value);
126+
public abstract Builder tolerateInvalidTypeExpressions(boolean value);
126127

127128
public abstract FileOptions build();
128129
}

src/main/java/net/starlark/java/syntax/Parser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ private Expression maybeParseTypeAnnotationAfter(TokenKind expectedToken) {
10891089
private Expression parseTypeExprWithFallback() {
10901090
Expression result;
10911091
this.insideTypeExpr = true;
1092-
if (options.allowArbitraryTypeExpressions()) {
1092+
if (options.tolerateInvalidTypeExpressions()) {
10931093
// parseTest, because allowing unparenthesized tuples here would consume subsequent params in
10941094
// function signatures.
10951095
result = parseTest();

src/test/java/net/starlark/java/eval/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ filegroup(
1313
java_test(
1414
name = "EvalTests",
1515
srcs = [
16+
"DynamicTypeCheckTest.java",
1617
"EvalTests.java", # (suite)
1718
"EvalUtilsTest.java",
1819
"EvaluationTest.java",
@@ -32,7 +33,6 @@ java_test(
3233
"StarlarkThreadDebuggingTest.java",
3334
"StarlarkThreadTest.java",
3435
"SymbolGeneratorTest.java",
35-
"TypeCheckTest.java",
3636
],
3737
jvm_flags = [
3838
"-Dfile.encoding=UTF8",

src/test/java/net/starlark/java/eval/TypeCheckTest.java renamed to src/test/java/net/starlark/java/eval/DynamicTypeCheckTest.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,30 @@
2828
import org.junit.runner.RunWith;
2929
import org.junit.runners.JUnit4;
3030

31-
/** Tests for Starlark types. */
31+
/** Tests for Starlark type checking at evaluation time. */
3232
@RunWith(JUnit4.class)
33-
public class TypeCheckTest {
33+
public class DynamicTypeCheckTest {
3434

3535
private EvaluationTestCase ev;
3636

3737
@Before
3838
public void setup() {
3939
ev = new EvaluationTestCase();
4040
ev.setFileOptions(FileOptions.builder().allowTypeSyntax(true).build());
41+
ev.setSemantics(
42+
StarlarkSemantics.builder()
43+
.setBool(StarlarkSemantics.EXPERIMENTAL_STARLARK_TYPE_CHECKING, true)
44+
.build());
45+
}
46+
47+
@Test
48+
public void typechecking_disabledByFlag() throws Exception {
49+
ev.setSemantics(
50+
StarlarkSemantics.builder()
51+
.setBool(StarlarkSemantics.EXPERIMENTAL_STARLARK_TYPE_CHECKING, false)
52+
.build());
53+
54+
ev.exec("def f(a : int): pass", "f('abc')");
4155
}
4256

4357
@Test

src/test/java/net/starlark/java/eval/EvalTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
/** EvalTests tests the Starlark evaluator. */
2020
@RunWith(Suite.class)
2121
@Suite.SuiteClasses({
22+
DynamicTypeCheckTest.class,
2223
EvaluationTest.class,
2324
EvalUtilsTest.class,
2425
FunctionTest.class,
@@ -34,6 +35,5 @@
3435
StarlarkMutableTest.class,
3536
StarlarkThreadDebuggingTest.class,
3637
StarlarkThreadTest.class,
37-
TypeCheckTest.class
3838
})
3939
public class EvalTests {}

0 commit comments

Comments
 (0)