Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:error_codes",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/resources/testdata/proto3:standalone_global_enum_java_proto",
"//common/testing",
Expand Down
6 changes: 5 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,6 +65,7 @@
import dev.cel.common.CelIssue;
import dev.cel.common.CelOptions;
import dev.cel.common.CelProtoAbstractSyntaxTree;
import dev.cel.common.CelSourceLocation;
import dev.cel.common.CelValidationException;
import dev.cel.common.CelValidationResult;
import dev.cel.common.CelVarDecl;
Expand DownExpand Up@@ -473,7 +474,10 @@ public void compile_typeCheckFailure() {
assertThat(syntaxErrorResult.hasError()).isTrue();
assertThat(syntaxErrorResult.getErrors())
.containsExactly(
CelIssue.formatError(1, 0, "undeclared reference to 'variable' (in container '')"));
CelIssue.formatError(
/* exprId= */ 1L,
CelSourceLocation.of(1, 0),
"undeclared reference to 'variable' (in container '')"));
assertThat(syntaxErrorResult.getErrorString())
.isEqualTo(
"ERROR: <input>:1:1: undeclared reference to 'variable' (in container '')\n"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -517,7 +517,11 @@ private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder.setMessage(e.rawMessage()).setSourceLocation(newLoc).build();
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}
Expand Down
34 changes: 25 additions & 9 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -490,10 +490,11 @@ public Env add(String name, Type type) {
* Lookup a name like {@link #tryLookupCelIdent}, but report an error if the name is not found and
* return the {@link #ERROR_IDENT_DECL}.
*/
public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
public CelIdentDecl lookupIdent(long exprId, int position, String inContainer, String name) {
CelIdentDecl result = tryLookupCelIdent(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_IDENT_DECL;
}
return result;
Expand All@@ -503,18 +504,30 @@ public CelIdentDecl lookupIdent(int position, String inContainer, String name) {
* Lookup a name like {@link #tryLookupCelFunction} but report an error if the name is not found
* and return the {@link #ERROR_FUNCTION_DECL}.
*/
public CelFunctionDecl lookupFunction(int position, String inContainer, String name) {
public CelFunctionDecl lookupFunction(
long exprId, int position, String inContainer, String name) {
CelFunctionDecl result = tryLookupCelFunction(inContainer, name);
if (result == null) {
reportError(position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
reportError(
exprId, position, "undeclared reference to '%s' (in container '%s')", name, inContainer);
return ERROR_FUNCTION_DECL;
}
return result;
}

/** Reports an error. */
/**
* Note: Used by codegen
*
* @deprecated Use {@link #reportError(long, int, String, Object...) instead.}
*/
@Deprecated
public void reportError(int position, String message, Object... args) {
errors.reportError(position, message, args);
reportError(0L, position, message, args);
}

/** Reports an error. */
public void reportError(long exprId, int position, String message, Object... args) {
errors.reportError(exprId, position, message, args);
}

boolean enableCompileTimeOverloadResolution() {
Expand DownExpand Up@@ -549,7 +562,8 @@ private Env addIdent(CelIdentDecl celIdentDecl) {
getDeclGroup().putIdent(celIdentDecl);
} else {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping declaration name '%s' (type '%s' cannot be distinguished from '%s')",
celIdentDecl.name(),
CelTypes.format(current.type()),
Expand DownExpand Up@@ -595,7 +609,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
|| Types.isAssignable(emptySubs, existingTypeErased, overloadTypeErased) != null;
if (overlap && existing.isInstanceFunction() == overload.isInstanceFunction()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overlapping overload for name '%s' (type '%s' cannot be distinguished from '%s')",
builder.name(),
CelTypes.format(existingFunction),
Expand All@@ -610,7 +625,8 @@ private void addOverload(CelFunctionDecl.Builder builder, CelOverloadDecl overlo
&& macro.getDefinition().isReceiverStyle() == overload.isInstanceFunction()
&& macro.getDefinition().getArgumentCount() == overload.parameterTypes().size()) {
reportError(
0,
/* exprId= */ 0,
/* position= */ 0,
"overload for name '%s' with %s argument(s) overlaps with predefined macro",
builder.name(),
macro.getDefinition().getArgumentCount());
Expand Down
76 changes: 52 additions & 24 deletions checker/src/main/java/dev/cel/checker/ExprChecker.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -232,7 +232,7 @@ private CelExpr visit(CelExpr expr, CelConstant constant) {

@CheckReturnValue
private CelExpr visit(CelExpr expr, CelExpr.CelIdent ident) {
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, ident.name());
CelIdentDecl decl = env.lookupIdent(expr.id(), getPosition(expr), inContainer, ident.name());
checkNotNull(decl);
if (decl.equals(Env.ERROR_IDENT_DECL)) {
// error reported
Expand All@@ -257,7 +257,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelSelect select) {
CelIdentDecl decl = env.tryLookupCelIdent(inContainer, qname);
if (decl != null) {
if (select.testOnly()) {
env.reportError(getPosition(expr), "expression does not select a field");
env.reportError(expr.id(), getPosition(expr), "expression does not select a field");
env.setType(expr, SimpleType.BOOL);
} else {
if (namespacedDeclarations) {
Expand DownExpand Up@@ -308,8 +308,8 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {

if (!call.target().isPresent()) {
// Regular static call with simple name.
CelFunctionDecl decl = env.lookupFunction(position, inContainer, call.function());
resolution = resolveOverload(position, decl, null, call.args());
CelFunctionDecl decl = env.lookupFunction(expr.id(), position, inContainer, call.function());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (!decl.name().equals(call.function())) {
if (namespacedDeclarations) {
Expand All@@ -323,7 +323,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
CelFunctionDecl decl =
env.tryLookupCelFunction(inContainer, qualifiedName + "." + call.function());
if (decl != null) {
resolution = resolveOverload(position, decl, null, call.args());
resolution = resolveOverload(expr.id(), position, decl, null, call.args());

if (namespacedDeclarations) {
// The function name is namespaced and so preserving the target operand would
Expand All@@ -342,8 +342,9 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
}
resolution =
resolveOverload(
expr.id(),
position,
env.lookupFunction(getPosition(expr), inContainer, call.function()),
env.lookupFunction(expr.id(), getPosition(expr), inContainer, call.function()),
target,
call.args());
}
Expand All@@ -359,18 +360,22 @@ private CelExpr visit(CelExpr expr, CelExpr.CelCall call) {
private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Determine the type of the message.
CelType messageType = SimpleType.ERROR;
CelIdentDecl decl = env.lookupIdent(getPosition(expr), inContainer, struct.messageName());
CelIdentDecl decl =
env.lookupIdent(expr.id(), getPosition(expr), inContainer, struct.messageName());
env.setRef(expr, CelReference.newBuilder().setName(decl.name()).build());
CelType type = decl.type();
if (type.kind() != CelKind.ERROR) {
if (type.kind() != CelKind.TYPE) {
// expected type of types
env.reportError(getPosition(expr), "'%s' is not a type", CelTypes.format(type));
env.reportError(expr.id(), getPosition(expr), "'%s' is not a type", CelTypes.format(type));
} else {
messageType = ((TypeType) type).type();
if (messageType.kind() != CelKind.STRUCT) {
env.reportError(
getPosition(expr), "'%s' is not a message type", CelTypes.format(messageType));
expr.id(),
getPosition(expr),
"'%s' is not a message type",
CelTypes.format(messageType));
messageType = SimpleType.ERROR;
}
}
Expand All@@ -392,18 +397,23 @@ private CelExpr visit(CelExpr expr, CelExpr.CelStruct struct) {
// Subtree has been rewritten. Replace the struct value.
expr = replaceStructEntryValueSubtree(expr, visitedValueExpr, i);
}
CelType fieldType = getFieldType(getPosition(entry), messageType, entry.fieldKey()).celType();
CelType fieldType =
getFieldType(entry.id(), getPosition(entry), messageType, entry.fieldKey()).celType();
CelType valueType = env.getType(visitedValueExpr);
if (entry.optionalEntry()) {
if (valueType instanceof OptionalType) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}
if (!inferenceContext.isAssignable(fieldType, valueType)) {
env.reportError(
expr.id(),
getPosition(entry),
"expected type of field '%s' is '%s' but provided type is '%s'",
entry.fieldKey(),
Expand All@@ -427,7 +437,11 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
expr = replaceMapEntryKeySubtree(expr, visitedMapKeyExpr, i);
}
mapKeyType =
joinTypes(getPosition(visitedMapKeyExpr), mapKeyType, env.getType(visitedMapKeyExpr));
joinTypes(
visitedMapKeyExpr.id(),
getPosition(visitedMapKeyExpr),
mapKeyType,
env.getType(visitedMapKeyExpr));

CelExpr visitedValueExpr = visit(entry.value());
if (namespacedDeclarations && !visitedValueExpr.equals(entry.value())) {
Expand All@@ -440,11 +454,15 @@ private CelExpr visit(CelExpr expr, CelExpr.CelMap map) {
valueType = unwrapOptional(valueType);
} else {
assertIsAssignable(
getPosition(visitedValueExpr), valueType, OptionalType.create(valueType));
visitedValueExpr.id(),
getPosition(visitedValueExpr),
valueType,
OptionalType.create(valueType));
}
}

mapValueType = joinTypes(getPosition(visitedValueExpr), mapValueType, valueType);
mapValueType =
joinTypes(visitedValueExpr.id(), getPosition(visitedValueExpr), mapValueType, valueType);
}
if (mapKeyType == null) {
// If the map is empty, assign free type variables to key and value type.
Expand All@@ -471,11 +489,12 @@ private CelExpr visit(CelExpr expr, CelExpr.CelList list) {
if (elemType instanceof OptionalType) {
elemType = unwrapOptional(elemType);
} else {
assertIsAssignable(getPosition(visitedElem), elemType, OptionalType.create(elemType));
assertIsAssignable(
visitedElem.id(), getPosition(visitedElem), elemType, OptionalType.create(elemType));
}
}

elemsType = joinTypes(getPosition(visitedElem), elemsType, elemType);
elemsType = joinTypes(visitedElem.id(), getPosition(visitedElem), elemsType, elemType);
}
if (elemsType == null) {
// If the list is empty, assign free type var to elem type.
Expand DownExpand Up@@ -514,6 +533,7 @@ private CelExpr visit(CelExpr expr, CelExpr.CelComprehension compre) {
break;
default:
env.reportError(
expr.id(),
getPosition(visitedRange),
"expression of type '%s' cannot be range of a comprehension "
+ "(must be list, map, or dynamic)",
Expand DownExpand Up@@ -563,6 +583,7 @@ private CelReference makeReference(CelIdentDecl decl) {
}

private OverloadResolution resolveOverload(
long callExprId,
int position,
@Nullable CelFunctionDecl function,
@Nullable CelExpr target,
Expand DownExpand Up@@ -620,6 +641,7 @@ private OverloadResolution resolveOverload(
if (compileTimeOverloadResolution) {
// In compile-time overload resolution mode report this situation as an error.
env.reportError(
callExprId,
position,
"found more than one matching overload for '%s' applied to '%s': %s and also %s",
function.name(),
Expand All@@ -634,6 +656,7 @@ private OverloadResolution resolveOverload(
}
if (resultType == null) {
env.reportError(
callExprId,
position,
"found no matching overload for '%s' applied to '%s'%s",
function.name(),
Expand All@@ -660,7 +683,8 @@ private CelType visitSelectField(

if (!Types.isDynOrError(operandType)) {
if (operandType.kind() == CelKind.STRUCT) {
TypeProvider.FieldType fieldType = getFieldType(getPosition(expr), operandType, field);
TypeProvider.FieldType fieldType =
getFieldType(expr.id(), getPosition(expr), operandType, field);
// Type of the field
resultType = fieldType.celType();
} else if (operandType.kind() == CelKind.MAP) {
Expand All@@ -679,6 +703,7 @@ private CelType visitSelectField(
resultType = SimpleType.DYN;
} else {
env.reportError(
expr.id(),
getPosition(expr),
"type '%s' does not support field selection",
CelTypes.format(operandType));
Expand All@@ -699,7 +724,7 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
CelExpr field = call.args().get(1);
if (!field.exprKind().getKind().equals(CelExpr.ExprKind.Kind.CONSTANT)
|| field.constant().getKind() != CelConstant.Kind.STRING_VALUE) {
env.reportError(getPosition(field), "unsupported optional field selection");
env.reportError(expr.id(), getPosition(field), "unsupported optional field selection");
return expr;
}

Expand DownExpand Up@@ -736,7 +761,8 @@ private CelExpr visitOptionalCall(CelExpr expr, CelExpr.CelCall call) {
}

/** Returns the field type give a type instance and field name. */
private TypeProvider.FieldType getFieldType(int position, CelType type, String fieldName) {
private TypeProvider.FieldType getFieldType(
long exprId, int position, CelType type, String fieldName) {
String typeName = type.name();
if (typeProvider.lookupCelType(typeName).isPresent()) {
TypeProvider.FieldType fieldType = typeProvider.lookupFieldType(type, fieldName);
Expand All@@ -748,11 +774,12 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
if (extensionFieldType != null) {
return extensionFieldType.fieldType();
}
env.reportError(position, "undefined field '%s'", fieldName);
env.reportError(exprId, position, "undefined field '%s'", fieldName);
} else {
// Proto message was added as a variable to the environment but the descriptor was not
// provided
env.reportError(
exprId,
position,
"Message type resolution failure while referencing field '%s'. Ensure that the descriptor"
+ " for type '%s' was added to the environment",
Expand All@@ -763,21 +790,22 @@ private TypeProvider.FieldType getFieldType(int position, CelType type, String f
}

/** Checks compatibility of joined types, and returns the most general common type. */
private CelType joinTypes(int position, CelType previousType, CelType type) {
private CelType joinTypes(long exprId, int position, CelType previousType, CelType type) {
if (previousType == null) {
return type;
}
if (homogeneousLiterals) {
assertIsAssignable(position, type, previousType);
assertIsAssignable(exprId, position, type, previousType);
} else if (!inferenceContext.isAssignable(previousType, type)) {
return SimpleType.DYN;
}
return Types.mostGeneral(previousType, type);
}

private void assertIsAssignable(int position, CelType actual, CelType expected) {
private void assertIsAssignable(long exprId, int position, CelType actual, CelType expected) {
if (!inferenceContext.isAssignable(expected, actual)) {
env.reportError(
exprId,
position,
"expected type '%s' but found '%s'",
CelTypes.format(expected),
Expand All@@ -790,7 +818,7 @@ private CelType unwrapOptional(CelType type) {
}

private void assertType(CelExpr expr, CelType type) {
assertIsAssignable(getPosition(expr), env.getType(expr), type);
assertIsAssignable(expr.id(), getPosition(expr), env.getType(expr), type);
}

private int getPosition(CelExpr expr) {
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/java/dev/cel/checker/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ java_library(
"//common:compiler_common",
"//common:options",
"//common:proto_ast",
"//common:source_location",
"//common/ast",
"//common/internal:env_visitor",
"//common/internal:errors",
Expand Down
Loading