private static void GetDisplayClassVariables( ArrayBuilder<string> displayClassVariableNamesInOrderBuilder, Dictionary<string, DisplayClassVariable> displayClassVariablesBuilder, HashSet<string> parameterNames, InScopeHoistedLocals inScopeHoistedLocals, DisplayClassInstanceAndFields instance, HashSet<string> hoistedParameterNames) { // Display class instance. The display class fields are variables. foreach (var member in instance.Type.GetMembers()) { if (member.Kind != SymbolKind.Field) { continue; } var field = (FieldSymbol)member; var fieldName = field.Name; REPARSE: DisplayClassVariableKind variableKind; string variableName; GeneratedNameKind fieldKind; int openBracketOffset; int closeBracketOffset; GeneratedNames.TryParseGeneratedName(fieldName, out fieldKind, out openBracketOffset, out closeBracketOffset); switch (fieldKind) { case GeneratedNameKind.AnonymousTypeField: Debug.Assert(fieldName == field.Name); // This only happens once. fieldName = fieldName.Substring(openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1); goto REPARSE; case GeneratedNameKind.TransparentIdentifier: // A transparent identifier (field) in an anonymous type synthesized for a transparent identifier. Debug.Assert(!field.IsStatic); continue; case GeneratedNameKind.DisplayClassLocalOrField: // A local that is itself a display class instance. Debug.Assert(!field.IsStatic); continue; case GeneratedNameKind.HoistedLocalField: // Filter out hoisted locals that are known to be out-of-scope at the current IL offset. // Hoisted locals with invalid indices will be included since more information is better // than less in error scenarios. if (!inScopeHoistedLocals.IsInScope(fieldName)) { continue; } variableName = fieldName.Substring(openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1); variableKind = DisplayClassVariableKind.Local; Debug.Assert(!field.IsStatic); break; case GeneratedNameKind.ThisProxyField: // A reference to "this". variableName = fieldName; variableKind = DisplayClassVariableKind.This; Debug.Assert(!field.IsStatic); break; case GeneratedNameKind.None: // A reference to a parameter or local. variableName = fieldName; if (parameterNames.Contains(variableName)) { variableKind = DisplayClassVariableKind.Parameter; hoistedParameterNames.Add(variableName); } else { variableKind = DisplayClassVariableKind.Local; } Debug.Assert(!field.IsStatic); break; default: continue; } if (displayClassVariablesBuilder.ContainsKey(variableName)) { // Only expecting duplicates for async state machine // fields (that should be at the top-level). Debug.Assert(displayClassVariablesBuilder[variableName].DisplayClassFields.Count() == 1); Debug.Assert(instance.Fields.Count() >= 1); // greater depth Debug.Assert((variableKind == DisplayClassVariableKind.Parameter) || (variableKind == DisplayClassVariableKind.This)); } else if (variableKind != DisplayClassVariableKind.This || GeneratedNames.GetKind(instance.Type.ContainingType.Name) != GeneratedNameKind.LambdaDisplayClass) { // In async lambdas, the hoisted "this" field in the state machine type will point to the display class instance, if there is one. // In such cases, we want to add the display class "this" to the map instead (or nothing, if it lacks one). displayClassVariableNamesInOrderBuilder.Add(variableName); displayClassVariablesBuilder.Add(variableName, instance.ToVariable(variableName, variableKind, field)); } } }