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); }
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); }
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); }
internal void CreateAssignmentEdge(TypeWithNode source, TypeWithNode target, EdgeLabel label) { CreateTypeEdge(source, target, null, VarianceKind.Out, label); }
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)); }