/// <summary> /// Finds variables that were assigned to and determines their types. /// </summary> /// <param name="root"> The root of the abstract syntax tree to search. </param> /// <param name="variableTypes"> A dictionary containing the variables that were assigned to. </param> /// <param name="conditional"> <c>true</c> if execution of the AST node <paramref name="root"/> /// is conditional (i.e. the node is inside an if statement or a conditional expression. </param> /// <param name="continueEncountered"> Keeps track of whether a continue statement has been /// encountered. </param> private static void FindTypedVariables(AstNode root, Dictionary <Scope.DeclaredVariable, InferredTypeInfo> variableTypes, bool conditional, ref bool continueEncountered) { if (root is AssignmentExpression) { // Found an assignment. var assignment = (AssignmentExpression)root; if (assignment.Target is NameExpression) { // Found an assignment to a variable. var name = (NameExpression)assignment.Target; if (name.Scope is DeclarativeScope) { var variable = name.Scope.GetDeclaredVariable(name.Name); if (variable != null) { // The variable is in the top-most scope. // Check if the variable has been seen before. InferredTypeInfo existingTypeInfo; if (variableTypes.TryGetValue(variable, out existingTypeInfo) == false) { // This is the first time the variable has been encountered. variableTypes.Add(variable, new InferredTypeInfo() { Type = assignment.ResultType, Conditional = conditional }); } else { // The variable has been seen before. variableTypes[variable] = new InferredTypeInfo() { Type = PrimitiveTypeUtilities.GetCommonType(existingTypeInfo.Type, assignment.ResultType), Conditional = existingTypeInfo.Conditional == true && conditional == true }; } } } } } // Determine whether the child nodes are conditional. conditional = conditional == true || continueEncountered == true || root is IfStatement || root is TernaryExpression || root is TryCatchFinallyStatement || (root is BinaryExpression && ((BinaryExpression)root).OperatorType == OperatorType.LogicalAnd) || (root is BinaryExpression && ((BinaryExpression)root).OperatorType == OperatorType.LogicalOr); // If the AST node is a continue statement, all further assignments are conditional. if (root is ContinueStatement) { continueEncountered = true; } // Search child nodes for assignment statements. foreach (var node in root.ChildNodes) { FindTypedVariables(node, variableTypes, conditional: conditional, continueEncountered: ref continueEncountered); } }