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
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public void endVisit(InstanceofExpression node) {

List<VariableElement> variablesToDeclare = new ArrayList<>();
Expression condition =
computePatternCondition(expression, node.getPattern(), variablesToDeclare);
computePatternCondition(
expression, node.getPattern(), /* allowUnconditional= */ false, variablesToDeclare);

for (var variableToDeclare : variablesToDeclare) {
// Initialize the patternVariables to null. The implementation of patterns in switches creates
Expand All @@ -124,7 +125,10 @@ public void endVisit(InstanceofExpression node) {
}

private Expression computePatternCondition(
Expression expression, Pattern pattern, List<VariableElement> variablesToDeclare) {
Expression expression,
Pattern pattern,
boolean allowUnconditional,
List<VariableElement> variablesToDeclare) {
switch (pattern) {
case BindingPattern bindingPattern -> {
VariableElement patternVariable = bindingPattern.getVariable().getVariableElement();
Expand All @@ -137,9 +141,12 @@ private Expression computePatternCondition(
.setTypeMirror(typeUtil.getBoolean());
}

boolean isUnconditional = allowUnconditional
&& typeUtil.isAssignable(
expression.getTypeMirror(), patternVariable.asType());

Expression instanceofLhs = expression.copy();
if (!(expression instanceof SimpleName)
&& !patternVariable.asType().getKind().isPrimitive()) {
if (!(expression instanceof SimpleName) && !isUnconditional) {
// Use a temporary variable to avoid evaluating the expression more than once and make
// sure that user written property getters that might have side-effects are only
// evaluated once.
Expand All @@ -154,9 +161,9 @@ private Expression computePatternCondition(
variablesToDeclare.add(patternVariable);
// expression instanceof T && (patternVariable = (T) expression, true)
return andCondition(
patternVariable.asType().getKind().isPrimitive()
// Primitives don't needs any checking. In the future when/if primitive patterns are
// incorporated in the Java language, this should be updated.
isUnconditional
// Unconditional patterns don't needs any checking. In the future when/if primitive
// patterns are incorporated in the Java language, this should be updated.
? null
: new InstanceofExpression()
.setLeftOperand(instanceofLhs)
Expand All @@ -178,7 +185,13 @@ private Expression computePatternCondition(
// (e instanceof Rec rec)
Expression condition =
computePatternCondition(
expression, new BindingPattern(tempVariable), variablesToDeclare);
expression,
new BindingPattern(tempVariable),
// The binding pattern resulting from the implementation of a deconstruction pattern
// cannot be uncondiional since its components will be accessed and hence it cannot
// allow nulls.
/* allowUnconditional */ false,
variablesToDeclare);

var recordType = (TypeElement) ((ClassType) deconstructionPattern.getTypeMirror()).tsym;
for (int i = 0; i < deconstructionPattern.getNestedPatterns().size(); i++) {
Expand All @@ -198,7 +211,9 @@ private Expression computePatternCondition(

condition =
andCondition(
condition, computePatternCondition(property, nestedPattern, variablesToDeclare));
condition,
computePatternCondition(
property, nestedPattern, /* allowUnconditional= */ true, variablesToDeclare));
}
return condition;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,18 +191,16 @@ void test() {
id comp = nil;
Test_A *rec_1 = nil;
int32_t i1 = 0;
NSString *comp_1 = nil;
NSString *s = nil;
int32_t i2 = 0;
Test_A *comp_2 = nil;
Test_A *a = nil;
id o = create_Test_B_initWithId_withInt_withTest_A_(create_Test_A_initWithInt_withNSString_(1, @""), 3, create_Test_A_initWithInt_withNSString_(2, @"bye"));
if ([o isKindOfClass:[Test_B class]] && (rec = (Test_B *) o, true)\
&& [comp = [((Test_B *) nil_chk(rec)) a1] isKindOfClass:[Test_A class]] && (rec_1 = (Test_A *) comp, true)\
&& (i1 = (int32_t) [((Test_A *) nil_chk(rec_1)) i], true)\
&& [comp_1 = [((Test_A *) nil_chk(rec_1)) s] isKindOfClass:[NSString class]] && (s = comp_1, true)\
&& (s = [((Test_A *) nil_chk(rec_1)) s], true)\
&& (i2 = (int32_t) [((Test_B *) nil_chk(rec)) i], true)\
&& [comp_2 = [((Test_B *) nil_chk(rec)) a2] isKindOfClass:[Test_A class]] && (a = comp_2, true)) {
&& (a = [((Test_B *) nil_chk(rec)) a2], true)) {
""");
}
}