Beispiel #1
0
        private BoundTupleLiteral DeconstructVariablesAsTuple(SyntaxNode syntax, ArrayBuilder <DeconstructionVariable> variables)
        {
            int count         = variables.Count;
            var valuesBuilder = ArrayBuilder <BoundExpression> .GetInstance(count);

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(count);

            var locationsBuilder = ArrayBuilder <Location> .GetInstance(count);

            foreach (var variable in variables)
            {
                if (variable.HasNestedVariables)
                {
                    var nestedTuple = DeconstructVariablesAsTuple(variable.Syntax, variable.NestedVariables);
                    valuesBuilder.Add(nestedTuple);
                    typesBuilder.Add(nestedTuple.Type);
                }
                else
                {
                    var single = variable.Single;
                    valuesBuilder.Add(single);
                    typesBuilder.Add(single.Type);
                }
                locationsBuilder.Add(variable.Syntax.Location);
            }

            // MakeDeconstructionConstructionStep constructs the final tuple type and checks constraints already.
            var type = TupleTypeSymbol.Create(syntax.Location,
                                              typesBuilder.ToImmutableAndFree(), locationsBuilder.ToImmutableAndFree(),
                                              elementNames: default(ImmutableArray <string>), compilation: this.Compilation, shouldCheckConstraints: false);

            return(new BoundTupleLiteral(syntax: syntax, argumentNamesOpt: default(ImmutableArray <string>),
                                         arguments: valuesBuilder.ToImmutableAndFree(), type: type));
        }
Beispiel #2
0
        private void AccessTupleFields(BoundDeconstructionAssignmentOperator node, BoundDeconstructionDeconstructStep deconstruction, ArrayBuilder <LocalSymbol> temps, ArrayBuilder <BoundExpression> stores, ArrayBuilder <BoundValuePlaceholderBase> placeholders)
        {
            var target            = PlaceholderReplacement(deconstruction.InputPlaceholder);
            var tupleType         = target.Type.IsTupleType ? target.Type : TupleTypeSymbol.Create((NamedTypeSymbol)target.Type);
            var tupleElementTypes = tupleType.TupleElementTypes;

            var numElements = tupleElementTypes.Length;

            SyntaxNode syntax = node.Syntax;

            // save the target as we need to access it multiple times
            BoundAssignmentOperator assignmentToTemp;
            BoundLocal savedTuple = _factory.StoreToTemp(target, out assignmentToTemp);

            stores.Add(assignmentToTemp);
            temps.Add(savedTuple.LocalSymbol);

            // list the tuple fields accessors
            var fields = tupleType.TupleElements;

            for (int i = 0; i < numElements; i++)
            {
                var field = fields[i];

                DiagnosticInfo useSiteInfo = field.GetUseSiteDiagnostic();
                if ((object)useSiteInfo != null && useSiteInfo.Severity == DiagnosticSeverity.Error)
                {
                    Symbol.ReportUseSiteDiagnostic(useSiteInfo, _diagnostics, syntax.Location);
                }
                var fieldAccess = MakeTupleFieldAccess(syntax, field, savedTuple, null, LookupResultKind.Empty);

                AddPlaceholderReplacement(deconstruction.OutputPlaceholders[i], fieldAccess);
                placeholders.Add(deconstruction.OutputPlaceholders[i]);
            }
        }
Beispiel #3
0
        private BoundTupleLiteral DeconstructionVariablesAsTuple(CSharpSyntaxNode syntax, ArrayBuilder <DeconstructionVariable> variables, DiagnosticBag diagnostics, bool hasErrors)
        {
            int count         = variables.Count;
            var valuesBuilder = ArrayBuilder <BoundExpression> .GetInstance(count);

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(count);

            var locationsBuilder = ArrayBuilder <Location> .GetInstance(count);

            foreach (var variable in variables)
            {
                if (variable.HasNestedVariables)
                {
                    var nestedTuple = DeconstructionVariablesAsTuple(variable.Syntax, variable.NestedVariables, diagnostics, hasErrors);
                    valuesBuilder.Add(nestedTuple);
                    typesBuilder.Add(nestedTuple.Type);
                }
                else
                {
                    var single = variable.Single;
                    valuesBuilder.Add(single);
                    typesBuilder.Add(single.Type);
                }
                locationsBuilder.Add(variable.Syntax.Location);
            }

            var type = TupleTypeSymbol.Create(syntax.Location,
                                              typesBuilder.ToImmutableAndFree(), locationsBuilder.ToImmutableAndFree(),
                                              elementNames: default(ImmutableArray <string>), compilation: this.Compilation,
                                              shouldCheckConstraints: !hasErrors, syntax: syntax, diagnostics: hasErrors ? null : diagnostics);

            return(new BoundTupleLiteral(syntax: syntax, argumentNamesOpt: default(ImmutableArray <string>),
                                         arguments: valuesBuilder.ToImmutableAndFree(), type: type));
        }
        private NamedTypeSymbol DecodeNamedType(NamedTypeSymbol type)
        {
            // First decode the type arguments
            var typeArgs    = type.TypeArgumentsNoUseSiteDiagnostics;
            var decodedArgs = DecodeTypeArguments(typeArgs);

            NamedTypeSymbol decodedType = type;

            // Now check the container
            NamedTypeSymbol containingType = type.ContainingType;
            NamedTypeSymbol decodedContainingType;

            if ((object)containingType != null && containingType.IsGenericType)
            {
                decodedContainingType = DecodeNamedType(containingType);
                Debug.Assert(decodedContainingType.IsGenericType);
            }
            else
            {
                decodedContainingType = containingType;
            }

            // Replace the type if necessary
            var containerChanged = !ReferenceEquals(decodedContainingType, containingType);
            var typeArgsChanged  = typeArgs != decodedArgs;

            if (typeArgsChanged || containerChanged)
            {
                var newTypeArgs = type.HasTypeArgumentsCustomModifiers
                    ? decodedArgs.SelectAsArray((t, i, m) => new TypeWithModifiers(t, m.GetTypeArgumentCustomModifiers(i)), type)
                    : decodedArgs.SelectAsArray(TypeMap.TypeSymbolAsTypeWithModifiers);

                if (containerChanged)
                {
                    decodedType = decodedType.OriginalDefinition.AsMember(decodedContainingType);
                    // If the type is nested, e.g. Outer<T>.Inner<V>, then Inner is definitely
                    // not a tuple, since we know all tuple-compatible types (System.ValueTuple)
                    // are not nested types. Thus, it is safe to return without checking if
                    // Inner is a tuple.
                    return(decodedType.ConstructIfGeneric(newTypeArgs));
                }

                decodedType = type.ConstructedFrom.Construct(newTypeArgs, unbound: false);
            }

            // Now decode into a tuple, if it is one
            int tupleCardinality;

            if (decodedType.IsTupleCompatible(out tupleCardinality))
            {
                var elementNames = EatElementNamesIfAvailable(tupleCardinality);

                Debug.Assert(elementNames.IsDefault || elementNames.Length == tupleCardinality);

                decodedType = TupleTypeSymbol.Create(decodedType, elementNames);
            }

            return(decodedType);
        }
Beispiel #5
0
        /// <summary>
        /// For cases where the RHS of a deconstruction-declaration is a tuple literal, we merge type information from both the LHS and RHS.
        /// For cases where the RHS of a deconstruction-assignment is a tuple literal, the type information from the LHS determines the merged type, since all variables have a type.
        /// Returns null if a merged tuple type could not be fabricated.
        /// </summary>
        private static TypeSymbol MakeMergedTupleType(ArrayBuilder <DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            int leftLength  = lhsVariables.Count;
            int rightLength = rhsLiteral.Arguments.Length;

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(leftLength);

            for (int i = 0; i < rightLength; i++)
            {
                BoundExpression element    = rhsLiteral.Arguments[i];
                TypeSymbol      mergedType = element.Type;

                if (i < leftLength)
                {
                    var variable = lhsVariables[i];
                    if (variable.HasNestedVariables)
                    {
                        if (element.Kind == BoundKind.TupleLiteral)
                        {
                            // (variables) on the left and (elements) on the right
                            mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, compilation, diagnostics);
                        }
                        else if ((object)mergedType == null)
                        {
                            // (variables) on the left and null on the right
                            Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                        }
                    }
                    else
                    {
                        if ((object)variable.Single.Type != null)
                        {
                            // typed-variable on the left
                            mergedType = variable.Single.Type;
                        }
                    }
                }
                else
                {
                    if ((object)mergedType == null)
                    {
                        // a typeless element on the right, matching no variable on the left
                        Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                    }
                }

                typesBuilder.Add(mergedType);
            }

            if (typesBuilder.Any(t => t == null))
            {
                typesBuilder.Free();
                return(null);
            }

            return(TupleTypeSymbol.Create(locationOpt: null, elementTypes: typesBuilder.ToImmutableAndFree(), elementLocations: default(ImmutableArray <Location>),
                                          elementNames: default(ImmutableArray <string>), compilation: compilation, diagnostics: diagnostics));
        }
Beispiel #6
0
        private NamedTypeSymbol TransformTupleType(NamedTypeSymbol tupleType, bool isContaining)
        {
            Debug.Assert(tupleType.IsTupleType);

            var underlying            = tupleType.TupleUnderlyingType;
            var transformedUnderlying = TransformNamedType(underlying, isContaining);

            return(TupleTypeSymbol.Create(transformedUnderlying, tupleType.TupleElementNames));
        }
Beispiel #7
0
        private BoundTupleLiteral DeconstructionVariablesAsTuple(CSharpSyntaxNode syntax, ArrayBuilder <DeconstructionVariable> variables, DiagnosticBag diagnostics, bool hasErrors)
        {
            int count         = variables.Count;
            var valuesBuilder = ArrayBuilder <BoundExpression> .GetInstance(count);

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(count);

            var locationsBuilder = ArrayBuilder <Location> .GetInstance(count);

            var namesBuilder = ArrayBuilder <string> .GetInstance(count);

            foreach (var variable in variables)
            {
                if (variable.HasNestedVariables)
                {
                    var nestedTuple = DeconstructionVariablesAsTuple(variable.Syntax, variable.NestedVariables, diagnostics, hasErrors);
                    valuesBuilder.Add(nestedTuple);
                    typesBuilder.Add(nestedTuple.Type);
                    namesBuilder.Add(null);
                }
                else
                {
                    var single = variable.Single;
                    valuesBuilder.Add(single);
                    typesBuilder.Add(single.Type);
                    namesBuilder.Add(ExtractDeconstructResultElementName(single));
                }
                locationsBuilder.Add(variable.Syntax.Location);
            }

            var uniqueFieldNames = PooledHashSet <string> .GetInstance();

            RemoveDuplicateInferredTupleNames(namesBuilder, uniqueFieldNames);
            uniqueFieldNames.Free();
            ImmutableArray <string> tupleNames = namesBuilder.ToImmutableAndFree();

            bool disallowInferredNames = this.Compilation.LanguageVersion.DisallowInferredTupleElementNames();
            var  inferredPositions     = tupleNames.SelectAsArray(n => n != null);

            var type = TupleTypeSymbol.Create(syntax.Location,
                                              typesBuilder.ToImmutableAndFree(), locationsBuilder.ToImmutableAndFree(),
                                              tupleNames, this.Compilation,
                                              shouldCheckConstraints: !hasErrors,
                                              errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray <bool>),
                                              syntax: syntax, diagnostics: hasErrors ? null : diagnostics);

            // Always track the inferred positions in the bound node, so that conversions don't produce a warning
            // for "dropped names" on tuple literal when the name was inferred.
            return(new BoundTupleLiteral(syntax, tupleNames, inferredPositions, arguments: valuesBuilder.ToImmutableAndFree(), type: type));
        }
Beispiel #8
0
        /// <summary>
        /// This method recurses through leftTargets, right and conversion at the same time.
        /// As it does, it collects side-effects into the proper buckets (init, deconstructions, conversions, assignments).
        ///
        /// The side-effects from the right initially go into the init bucket. But once we started drilling into a Deconstruct
        /// invocation, subsequent side-effects from the right go into the deconstructions bucket (otherwise they would
        /// be evaluated out of order).
        /// </summary>
        private BoundTupleLiteral ApplyDeconstructionConversion(ArrayBuilder <Binder.DeconstructionVariable> leftTargets,
                                                                BoundExpression right, Conversion conversion, ArrayBuilder <LocalSymbol> temps, DeconstructionSideEffects effects,
                                                                bool inInit)
        {
            Debug.Assert(conversion.Kind == ConversionKind.Deconstruction);
            ImmutableArray <BoundExpression> rightParts = GetRightParts(right, conversion, ref temps, effects, ref inInit);

            ImmutableArray <Conversion> underlyingConversions = conversion.UnderlyingConversions;

            Debug.Assert(!underlyingConversions.IsDefault);
            Debug.Assert(leftTargets.Count == rightParts.Length && leftTargets.Count == conversion.UnderlyingConversions.Length);

            var builder = ArrayBuilder <BoundExpression> .GetInstance(leftTargets.Count);

            for (int i = 0; i < leftTargets.Count; i++)
            {
                BoundExpression resultPart;
                if (leftTargets[i].HasNestedVariables)
                {
                    resultPart = ApplyDeconstructionConversion(leftTargets[i].NestedVariables, rightParts[i],
                                                               underlyingConversions[i], temps, effects, inInit);
                }
                else
                {
                    var rightPart = rightParts[i];
                    if (inInit)
                    {
                        rightPart = EvaluateSideEffectingArgumentToTemp(VisitExpression(rightPart), inInit ? effects.init : effects.deconstructions, ref temps);
                    }
                    BoundExpression leftTarget = leftTargets[i].Single;

                    resultPart = EvaluateConversionToTemp(rightPart, underlyingConversions[i], leftTarget.Type, temps,
                                                          effects.conversions);

                    if (leftTarget.Kind != BoundKind.DiscardExpression)
                    {
                        effects.assignments.Add(MakeAssignmentOperator(resultPart.Syntax, leftTarget, resultPart, leftTarget.Type,
                                                                       used: true, isChecked: false, isCompoundAssignment: false));
                    }
                }
                builder.Add(resultPart);
            }

            var tupleType = TupleTypeSymbol.Create(locationOpt: null, elementTypes: builder.SelectAsArray(e => e.Type),
                                                   elementLocations: default(ImmutableArray <Location>), elementNames: default(ImmutableArray <string>),
                                                   compilation: _compilation, shouldCheckConstraints: false);

            return(new BoundTupleLiteral(right.Syntax, default(ImmutableArray <string>), builder.ToImmutableAndFree(), tupleType));
        }
Beispiel #9
0
        private NamedTypeSymbol TransformTupleType(NamedTypeSymbol tupleType, bool isContaining)
        {
            Debug.Assert(tupleType.IsTupleType);

            var underlying            = tupleType.TupleUnderlyingType;
            var transformedUnderlying = TransformNamedType(underlying, isContaining);

            if ((object)transformedUnderlying == null)
            {
                // Bail, something is wrong with the flags.
                // the dynamic transformation should be ignored.
                return(null);
            }

            return(TupleTypeSymbol.Create(transformedUnderlying, tupleType.TupleElementNames));
        }
Beispiel #10
0
        private BoundTupleLiteral DeconstructionVariablesAsTuple(CSharpSyntaxNode syntax, ArrayBuilder <DeconstructionVariable> variables,
                                                                 DiagnosticBag diagnostics, bool ignoreDiagnosticsFromTuple)
        {
            int count         = variables.Count;
            var valuesBuilder = ArrayBuilder <BoundExpression> .GetInstance(count);

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(count);

            var locationsBuilder = ArrayBuilder <Location> .GetInstance(count);

            var namesBuilder = ArrayBuilder <string> .GetInstance(count);

            foreach (var variable in variables)
            {
                if (variable.HasNestedVariables)
                {
                    var nestedTuple = DeconstructionVariablesAsTuple(variable.Syntax, variable.NestedVariables, diagnostics, ignoreDiagnosticsFromTuple);
                    valuesBuilder.Add(nestedTuple);
                    typesBuilder.Add(nestedTuple.Type);
                    namesBuilder.Add(null);
                }
                else
                {
                    var single = variable.Single;
                    valuesBuilder.Add(single);
                    typesBuilder.Add(single.Type);
                    namesBuilder.Add(ExtractDeconstructResultElementName(single));
                }
                locationsBuilder.Add(variable.Syntax.Location);
            }

            var uniqueFieldNames = PooledHashSet <string> .GetInstance();

            RemoveDuplicateInferredTupleNames(namesBuilder, uniqueFieldNames);
            uniqueFieldNames.Free();
            ImmutableArray <string> tupleNames = namesBuilder.ToImmutableAndFree();

            bool disallowInferredNames = this.Compilation.LanguageVersion.DisallowInferredTupleElementNames();
            var  inferredPositions     = tupleNames.SelectAsArray(n => n != null);

            var type = TupleTypeSymbol.Create(syntax.Location,
                                              typesBuilder.ToImmutableAndFree(), locationsBuilder.ToImmutableAndFree(),
                                              tupleNames, this.Compilation,
                                              shouldCheckConstraints: !ignoreDiagnosticsFromTuple,
                                              errorPositions: disallowInferredNames ? inferredPositions : default,
Beispiel #11
0
        private BoundDeconstructionConstructionStep MakeDeconstructionConstructionStep(CSharpSyntaxNode node, DiagnosticBag diagnostics,
                                                                                       ImmutableArray <BoundDeconstructValuePlaceholder> constructionInputs)
        {
            var tuple = TupleTypeSymbol.Create(locationOpt: null,
                                               elementTypes: constructionInputs.SelectAsArray(e => e.Type),
                                               elementLocations: default(ImmutableArray <Location>),
                                               elementNames: default(ImmutableArray <string>),
                                               compilation: Compilation,
                                               diagnostics: diagnostics,
                                               syntax: node);

            var outputPlaceholder = new BoundDeconstructValuePlaceholder(node, tuple)
            {
                WasCompilerGenerated = true
            };

            BoundExpression construction = new BoundTupleLiteral(node, default(ImmutableArray <string>), constructionInputs.CastArray <BoundExpression>(), tuple);

            return(new BoundDeconstructionConstructionStep(node, construction, outputPlaceholder));
        }
Beispiel #12
0
        /// <summary>
        /// For cases where the RHS of a deconstruction-declaration is a tuple literal, we merge type information from both the LHS and RHS.
        /// For cases where the RHS of a deconstruction-assignment is a tuple literal, the type information from the LHS determines the merged type, since all variables have a type.
        /// Returns null if a merged tuple type could not be fabricated.
        /// </summary>
        private static TypeSymbol MakeMergedTupleType(ArrayBuilder <DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            int leftLength  = lhsVariables.Count;
            int rightLength = rhsLiteral.Arguments.Length;

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(leftLength);

            var locationsBuilder = ArrayBuilder <Location> .GetInstance(leftLength);

            for (int i = 0; i < rightLength; i++)
            {
                BoundExpression element    = rhsLiteral.Arguments[i];
                TypeSymbol      mergedType = element.Type;

                if (i < leftLength)
                {
                    var variable = lhsVariables[i];
                    if (variable.HasNestedVariables)
                    {
                        if (element.Kind == BoundKind.TupleLiteral)
                        {
                            // (variables) on the left and (elements) on the right
                            mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, compilation, diagnostics);
                        }
                        else if ((object)mergedType == null)
                        {
                            // (variables) on the left and null on the right
                            Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                        }
                    }
                    else
                    {
                        if ((object)variable.Single.Type != null)
                        {
                            // typed-variable on the left
                            mergedType = variable.Single.Type;
                        }
                    }
                }
                else
                {
                    if ((object)mergedType == null)
                    {
                        // a typeless element on the right, matching no variable on the left
                        Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                    }
                }

                typesBuilder.Add(mergedType);
                locationsBuilder.Add(element.Syntax.Location);
            }

            if (typesBuilder.Any(t => t == null))
            {
                typesBuilder.Free();
                locationsBuilder.Free();
                return(null);
            }

            // The tuple created here is not identical to the one created by
            // DeconstructionVariablesAsTuple. It represents a smaller
            // tree of types used for figuring out natural types in tuple literal.
            return(TupleTypeSymbol.Create(
                       locationOpt: null,
                       elementTypes: typesBuilder.ToImmutableAndFree(),
                       elementLocations: locationsBuilder.ToImmutableAndFree(),
                       elementNames: default(ImmutableArray <string>),
                       compilation: compilation,
                       diagnostics: diagnostics,
                       shouldCheckConstraints: true,
                       errorPositions: default(ImmutableArray <bool>),
                       syntax: syntax));
        }
            public override Symbol VisitNamedType(NamedTypeSymbol sourceType)
            {
                var originalDef = sourceType.OriginalDefinition;

                if ((object)originalDef != (object)sourceType)
                {
                    HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                    var typeArguments = sourceType.GetAllTypeArguments(ref useSiteDiagnostics);

                    var otherDef = (NamedTypeSymbol)this.Visit(originalDef);
                    if ((object)otherDef == null)
                    {
                        return(null);
                    }

                    var  otherTypeParameters = otherDef.GetAllTypeParameters();
                    bool translationFailed   = false;

                    var otherTypeArguments = typeArguments.SelectAsArray((t, v) =>
                    {
                        var newType = (TypeSymbol)v.Visit(t.Type);

                        if ((object)newType == null)
                        {
                            // For a newly added type, there is no match in the previous generation, so it could be null.
                            translationFailed = true;
                            newType           = t.Type;
                        }

                        return(new TypeWithModifiers(newType, v.VisitCustomModifiers(t.CustomModifiers)));
                    }, this);

                    if (translationFailed)
                    {
                        // For a newly added type, there is no match in the previous generation, so it could be null.
                        return(null);
                    }

                    // TODO: LambdaFrame has alpha renamed type parameters, should we rather fix that?
                    var typeMap = new TypeMap(otherTypeParameters, otherTypeArguments, allowAlpha: true);
                    return(typeMap.SubstituteNamedType(otherDef));
                }
                else if (sourceType.IsTupleType)
                {
                    var otherDef = (NamedTypeSymbol)this.Visit(sourceType.TupleUnderlyingType);
                    if ((object)otherDef == null || !otherDef.IsTupleOrCompatibleWithTupleOfCardinality(sourceType.TupleElementTypes.Length))
                    {
                        return(null);
                    }

                    return(TupleTypeSymbol.Create(otherDef, sourceType.TupleElementNames));
                }

                Debug.Assert(sourceType.IsDefinition);

                var otherContainer = this.Visit(sourceType.ContainingSymbol);

                // Containing type will be missing from other assembly
                // if the type was added in the (newer) source assembly.
                if ((object)otherContainer == null)
                {
                    return(null);
                }

                switch (otherContainer.Kind)
                {
                case SymbolKind.Namespace:
                    if (AnonymousTypeManager.IsAnonymousTypeTemplate(sourceType))
                    {
                        Debug.Assert((object)otherContainer == (object)_otherAssembly.GlobalNamespace);
                        AnonymousTypeValue value;
                        this.TryFindAnonymousType(sourceType, out value);
                        return((NamedTypeSymbol)value.Type);
                    }
                    else if (sourceType.IsAnonymousType)
                    {
                        return(this.Visit(AnonymousTypeManager.TranslateAnonymousTypeSymbol(sourceType)));
                    }
                    else
                    {
                        return(FindMatchingNamespaceMember((NamespaceSymbol)otherContainer, sourceType, AreNamedTypesEqual));
                    }

                case SymbolKind.NamedType:
                    return(FindMatchingNamedTypeMember((NamedTypeSymbol)otherContainer, sourceType, AreNamedTypesEqual));

                default:
                    throw ExceptionUtilities.UnexpectedValue(otherContainer.Kind);
                }
            }