Пример #1
0
 public Builder(TypeSystem typeSystem)
 {
     // Don't store the typeSystem in this; we may not access it outside of Flush().
     this.NullableNode  = typeSystem.NullableNode;
     this.NonNullNode   = typeSystem.NonNullNode;
     this.ObliviousNode = typeSystem.ObliviousNode;
     this.VoidType      = typeSystem.VoidType;
 }
            public void AddBaseType(INamedTypeSymbol derivedType, TypeWithNode baseType)
            {
                if (baseType.Type == null)
                {
                    return;
                }
                var key = (derivedType.OriginalDefinition, baseType.Type.OriginalDefinition);

                AddAction(ts => ts.baseTypes[key] = baseType);
            }
Пример #3
0
            public void AddBaseType(INamedTypeSymbol derivedType, TypeWithNode baseType)
            {
                if (baseType.Type == null)
                {
                    return;
                }
                Debug.Assert(SymbolEqualityComparer.Default.Equals(derivedType, derivedType.OriginalDefinition));
                var key = (derivedType.OriginalDefinition, baseType.Type);

                AddAction(ts => ts.baseTypes[key] = baseType);
            }
Пример #4
0
            internal void CreateTypeEdge(TypeWithNode source, TypeWithNode target, TypeSubstitution?targetSubstitution, VarianceKind variance, EdgeLabel label)
            {
#if DEBUG
                if (source.FlowLabel != null)
                {
                    label = new EdgeLabel($"{label}\n{source.FlowLabel}");
                }
#endif
                if (targetSubstitution != null && target.Type is ITypeParameterSymbol tp)
                {
                    // If calling `void SomeCall<T>(T x);` as `SomeCall<string>(null)`, then
                    // we need either `x: T?` or `T = string?`:
                    //   (source is nullable) implies (target is nullable || substitutedTarget is nullable)
                    // We can't represent such a choice in the graph, so we always substitute and prefer `string?`.

                    // However, if the variance causes us to create edges the other way around
                    // (e.g. an override-edge for `override void SomeCall(string x)`), we have:
                    //   (target is nullable || substitutedTarget is nullable) implies (source is nullable)
                    // This can be represented by using two edges.
                    if (variance == VarianceKind.In || variance == VarianceKind.None)
                    {
                        CreateEdge(target.Node, source.Node, label);
                    }

                    // Perform the substitution:
                    target             = targetSubstitution.Value[tp.TypeParameterKind, tp.FullOrdinal()];
                    targetSubstitution = null;
                }
                Debug.Assert(source.Type?.TypeKind == target.Type?.TypeKind, "Type kinds do not match");
                if (source.Type is INamedTypeSymbol namedType)
                {
                    if (!SymbolEqualityComparer.Default.Equals(source.Type?.OriginalDefinition, target.Type?.OriginalDefinition))
                    {
                        throw new InvalidOperationException($"Types don't match: {source.Type} vs. {target.Type}");
                    }
                    var namedTypeTypeParameters = namedType.FullTypeParameters().ToList();
                    Debug.Assert(source.TypeArguments.Count == namedTypeTypeParameters.Count);
                    Debug.Assert(target.TypeArguments.Count == namedTypeTypeParameters.Count);
                    for (int i = 0; i < namedTypeTypeParameters.Count; i++)
                    {
                        var sourceArg        = source.TypeArguments[i];
                        var targetArg        = target.TypeArguments[i];
                        var combinedVariance = (variance, namedTypeTypeParameters[i].Variance).Combine();
            internal NullabilityEdge?CreateTypeEdge(TypeWithNode source, TypeWithNode target, TypeSubstitution?targetSubstitution, VarianceKind variance)
            {
                if (targetSubstitution != null && target.Type is ITypeParameterSymbol tp)
                {
                    // Perform the substitution:
                    target             = targetSubstitution.Value[tp.TypeParameterKind, tp.FullOrdinal()];
                    targetSubstitution = null;
                }
                Debug.Assert(source.Type?.TypeKind == target.Type?.TypeKind);
                if (source.Type is INamedTypeSymbol namedType)
                {
                    if (!SymbolEqualityComparer.Default.Equals(source.Type?.OriginalDefinition, target.Type?.OriginalDefinition))
                    {
                        throw new InvalidOperationException($"Types don't match: {source.Type} vs. {target.Type}");
                    }
                    var namedTypeTypeParameters = namedType.FullTypeParameters().ToList();
                    Debug.Assert(source.TypeArguments.Count == namedTypeTypeParameters.Count);
                    Debug.Assert(target.TypeArguments.Count == namedTypeTypeParameters.Count);
                    for (int i = 0; i < namedTypeTypeParameters.Count; i++)
                    {
                        tp = namedTypeTypeParameters[i];
                        var sourceArg        = source.TypeArguments[i];
                        var targetArg        = target.TypeArguments[i];
                        var combinedVariance = (variance, tp.Variance).Combine();
                        CreateTypeEdge(sourceArg, targetArg, targetSubstitution, combinedVariance);
                    }
                }
                else if (source.Type is IArrayTypeSymbol || source.Type is IPointerTypeSymbol)
                {
                    CreateTypeEdge(source.TypeArguments.Single(), target.TypeArguments.Single(), targetSubstitution, variance);
                }
                NullabilityEdge?edge = null;

                if (variance == VarianceKind.In || variance == VarianceKind.None)
                {
                    edge = CreateEdge(target.Node, source.Node);
                }
                if (variance == VarianceKind.Out || variance == VarianceKind.None)
                {
                    edge = CreateEdge(source.Node, target.Node);
                }
                return(edge);
            }
Пример #6
0
 internal void CreateAssignmentEdge(TypeWithNode source, TypeWithNode target, EdgeLabel label)
 {
     CreateTypeEdge(source, target, null, VarianceKind.Out, label);
 }
Пример #7
0
 public void AddSymbolType(ISymbol symbol, TypeWithNode type)
 {
     type.SetName(symbol.Name);
     AddAction(ts => ts.symbolType.Add(symbol, type));
 }
 internal NullabilityEdge?CreateAssignmentEdge(TypeWithNode source, TypeWithNode target)
 {
     return(CreateTypeEdge(source, target, null, VarianceKind.Out));
 }