Interface ITypeComputer

  • All Known Implementing Classes:
    XbaseTypeComputer, XbaseWithAnnotationsTypeComputer

    public interface ITypeComputer
    The type computer is the central component when it comes to type inferrence for expressions. Implementations will usually inherit from XbaseTypeComputer or XbaseWithAnnotationsTypeComputer and add new expressions by means of overriding computeTypes(XExpression, ITypeComputationState) and adding respective cases. Implementations are responsible for triggering type inference for all child expressions. There are three base idioms when implementing type inference for a given expression.
    Expression type is independent from expectations.
    This is the simplest case. There is no need to take expectations into account. The computed type is directly propagated to the current state. An example for this are boolean literals.
     void computeType(XBooleanLiteral literal, ITypeComputationState state) {
            LightweightTypeReference bool = getTypeForName(Boolean.TYPE, state);
            state.acceptActualType(bool);
     }
     
    The announced type is immediately propagated to all expectations. This is done by the inference framework.
    Expression type depends on the expectation.
    The expected type may steer the inferred type of an expression. Therefore the state may be queried for the currently known expectations and the produced type may be adjusted accordingly. String literals are a good example for this mechanism. Literals with exactly one character may be seen as character literals if the expected type suggests that. A simplified implementation could look like this.
     void computeType(XStringLiteral literal, ITypeComputationState state) {
      if (literal.getValue().length() == 1) {
        for(ITypeExpectation expectation: state.getExpectations() {
          LightweightTypeReference expectedType = expectation.getExpectedType();
          if (expectedType.isType(Character.TYPE) || expectedType.isType(Character.class)) {
            expectation.acceptActualType(expectedType, ConformanceHint.SUCCESS, ConformanceHint.CHECKED);
          } else {
            LightweightTypeReference string = getTypeForName(String.class, state);
                  state.acceptActualType(string);
          }
        }
      } else {
        LightweightTypeReference string = getTypeForName(String.class, state);
              state.acceptActualType(string);
      }
     }
     
    The type of an expression depends on its children.
    Expression types may be inferred from the types of contained children. Therefore the given computation state is directly used to compute their types. The framework will automatically propagate the common type of all children to the parent. If- or Switch expression fall into this category. A simplified implementation would again look like this:
     void computeTypes(XIfExpression expression, ITypeComputationState state) {
      state.withExpectations(getTypeForName(Boolean.TYPE, state).computeTypes(expression.getIfExpression());
      state.computeTypes(expression.getThen());
      state.computeTypes(expression.getElse());
     }
     
    The If expression adjusts the expectation for one of its children and computes its type. Afterwards, it directly reuses the current expectations to compute the types of its branch expressions. The common super type of those is assigned to the If expression by the framework.
    • Method Detail

      • computeTypes

        void computeTypes​(XExpression expression,
                          ITypeComputationState state)
        Compute the type for the given expression in the context of the given computation state. The state may be used to compute child types but implementations may not invoke this method recursively on their own. The framework handles the control flow.
        See Also:
        ITypeComputationState.computeTypes(XExpression)