Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-8337

STC: instanceof in ternary expression not propagating type info to true expression

    Details

      Description

      @CompileStatic
      class Static {
        private Number n
        BigDecimal meth() {
          return n == null || n instanceof BigDecimal ? n : new BigDecimal(n.toString())
        }
      }
      

      StaticTypeCheckingVisitor is missing the temporary type of the true expression part of the ternary expression because it pops before accessing the type. One possible solution:

          @Override
          public void visitTernaryExpression(final TernaryExpression expression) {
              Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
              // create a new temporary element in the if-then-else type info
              typeCheckingContext.pushTemporaryTypeInfo();
              expression.getBooleanExpression().visit(this);
              Expression trueExpression = expression.getTrueExpression();
              Expression falseExpression = expression.getFalseExpression();
              trueExpression.visit(this);
              // GRECLIPSE add
              final ClassNode typeOfTrue = findCurrentInstanceOfClass(trueExpression, getType(trueExpression));
              // GRECLIPSE end
              // pop if-then-else temporary type info
              typeCheckingContext.popTemporaryTypeInfo();
              falseExpression.visit(this);
              ClassNode resultType;
              if (isNullConstant(trueExpression) || isNullConstant(falseExpression)) {
                  BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
                  if (enclosingBinaryExpression != null && enclosingBinaryExpression.getRightExpression()==expression) {
                      resultType = getType(enclosingBinaryExpression.getLeftExpression());
                  } else if (isNullConstant(trueExpression) && isNullConstant(falseExpression)) {
                      resultType = OBJECT_TYPE;
                  } else if (isNullConstant(trueExpression)) {
                      resultType = wrapTypeIfNecessary(getType(falseExpression));
                  } else {
                      resultType = wrapTypeIfNecessary(getType(trueExpression));
                  }
              } else {
                  // store type information
                  // GRECLIPSE edit
                  //final ClassNode typeOfTrue = getType(trueExpression);
                  // GRECLIPSE end
                  final ClassNode typeOfFalse = getType(falseExpression);
                  resultType = lowestUpperBound(typeOfTrue, typeOfFalse);
              }
              storeType(expression, resultType);
              popAssignmentTracking(oldTracker);
          }
      

        Attachments

          Activity

            People

            • Assignee:
              daniel_sun Daniel Sun
              Reporter:
              emilles Eric Milles
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: