private DataType InferUnaryExpressionType(UnaryExpressionSyntax unaryExpression) { var operandType = InferExpressionType(unaryExpression.Operand); var @operator = unaryExpression.Operator; // If either is unknown, then we can't know whether there is a a problem // (technically not true, for example, we could know that one arg should // be a bool and isn't) if (operandType == DataType.Unknown) { return(unaryExpression.Type = DataType.Unknown); } bool typeError; switch (@operator) { case UnaryOperator.Not: typeError = operandType != DataType.Bool; unaryExpression.Type = DataType.Bool; break; case UnaryOperator.At: typeError = false; // TODO check that the expression can have a pointer taken if (operandType is Metatype) { unaryExpression.Type = DataType.Type; // constructing a type } else { unaryExpression.Type = new PointerType(operandType); // taking the address of something } break; case UnaryOperator.Question: typeError = false; // TODO check that the expression can have a pointer taken unaryExpression.Type = new PointerType(operandType); break; case UnaryOperator.Caret: switch (operandType) { case PointerType pointerType: unaryExpression.Type = pointerType.Referent; typeError = false; break; default: unaryExpression.Type = DataType.Unknown; typeError = true; break; } break; case UnaryOperator.Minus: switch (operandType) { case IntegerConstantType integerType: typeError = false; unaryExpression.Type = integerType; break; case SizedIntegerType sizedIntegerType: typeError = false; unaryExpression.Type = sizedIntegerType; break; default: unaryExpression.Type = DataType.Unknown; typeError = true; break; } break; default: throw NonExhaustiveMatchException.ForEnum(@operator); } if (typeError) { diagnostics.Add(TypeError.OperatorCannotBeAppliedToOperandOfType(file, unaryExpression.Span, @operator, operandType)); } return(unaryExpression.Type); }