/// <summary> /// Create an instance setting <see cref="IsNullable"/> lazily from /// <see cref="NonNullTypesContext"/> and <see cref="IsAnnotated"/>. /// </summary> /// <remarks> /// Should be used for scenarios where calculating <see cref="IsNullable"/> eagerly /// may result in cycles (when binding member declarations for instance). /// </remarks> internal static TypeSymbolWithAnnotations Create(INonNullTypesContext nonNullTypesContext, TypeSymbol typeSymbol, bool isAnnotated = false, ImmutableArray <CustomModifier> customModifiers = default) { Debug.Assert(nonNullTypesContext != null); Debug.Assert((nonNullTypesContext as Symbol)?.IsDefinition != false); if (typeSymbol is null) { return(default);
internal ImmutableArray <TypeSymbolWithAnnotations> GetTypeParametersAsTypeArguments() { // Resolving [NonNullTypes] only makes sense within the definition of the generic type or method. // If this is a substituted symbol, we use a dummy NonNullTypes context. var definition = OriginalDefinition; INonNullTypesContext nonNullTypesContext = (object)this == definition ? definition : NonNullTypesFalseContext.Instance; return(GetTypeParametersAsTypeArguments(nonNullTypesContext)); }
private TypeSymbolWithAnnotations(TypeSymbol defaultType, INonNullTypesContext nonNullTypesContext, bool isAnnotated, bool treatPossiblyNullableReferenceTypeTypeParameterAsNullable, Extensions extensions) { Debug.Assert((object)defaultType != null); Debug.Assert(!defaultType.IsNullableType() || isAnnotated); Debug.Assert(nonNullTypesContext != null); Debug.Assert(extensions != null); _defaultType = defaultType; IsAnnotated = isAnnotated; _treatPossiblyNullableReferenceTypeTypeParameterAsNullable = treatPossiblyNullableReferenceTypeTypeParameterAsNullable; NonNullTypesContext = nonNullTypesContext; _extensions = extensions; }
internal TypeMap WithConcatAlphaRename( MethodSymbol oldOwner, Symbol newOwner, INonNullTypesContext nonNullTypesContext, out ImmutableArray <TypeParameterSymbol> newTypeParameters, out ImmutableArray <TypeParameterSymbol> oldTypeParameters, MethodSymbol stopAt = null) { Debug.Assert(oldOwner.ConstructedFrom == oldOwner); Debug.Assert(stopAt == null || stopAt.ConstructedFrom == stopAt); // Build the array up backwards, then reverse it. // The following example goes through the do-loop in order M3, M2, M1 // but the type parameters have to be <T1, T2, T3, T4> // void M1<T1>() { // void M2<T2, T3>() { // void M3<T4>() { // } // } // } // However, if stopAt is M1, then the type parameters would be <T2, T3, T4> // That is, stopAt's type parameters are excluded - the parameters are in the range (stopAt, oldOwner] // A null stopAt means "include everything" var parameters = ArrayBuilder <TypeParameterSymbol> .GetInstance(); while (oldOwner != null && oldOwner != stopAt) { var currentParameters = oldOwner.OriginalDefinition.TypeParameters; for (int i = currentParameters.Length - 1; i >= 0; i--) { parameters.Add(currentParameters[i]); } oldOwner = oldOwner.ContainingSymbol.OriginalDefinition as MethodSymbol; } parameters.ReverseContents(); // Ensure that if stopAt was provided, it actually was in the chain and we stopped at it. // If not provided, both should be null (if stopAt != null && oldOwner == null, then it wasn't in the chain). // Alternately, we were inside a field initializer, in which case we were to stop at the constructor, // but never made it that far because we encountered the field in the ContainingSymbol chain. Debug.Assert( stopAt == oldOwner || stopAt?.MethodKind == MethodKind.StaticConstructor || stopAt?.MethodKind == MethodKind.Constructor); oldTypeParameters = parameters.ToImmutableAndFree(); return(WithAlphaRename(oldTypeParameters, newOwner, nonNullTypesContext, out newTypeParameters)); }
/// <summary> /// If the type reference has an associated NullableAttribute, this method /// returns the type transformed to have IsNullable set to true or false /// (but not null) for each reference type in the type. /// </summary> internal static TypeSymbolWithAnnotations TransformType( TypeSymbolWithAnnotations metadataType, EntityHandle targetSymbolToken, PEModuleSymbol containingModule, INonNullTypesContext nonNullTypesContext) { Debug.Assert(!metadataType.IsNull); ImmutableArray <bool> nullableTransformFlags; containingModule.Module.HasNullableAttribute(targetSymbolToken, out nullableTransformFlags); return(TransformType(metadataType, nullableTransformFlags, nonNullTypesContext)); }
// https://github.com/dotnet/roslyn/issues/29821 external annotations should be removed or fully designed/productized internal static TypeSymbolWithAnnotations TransformType( TypeSymbolWithAnnotations metadataType, EntityHandle targetSymbolToken, PEModuleSymbol containingModule, INonNullTypesContext nonNullTypesContext, ImmutableArray <bool> extraAnnotations) { if (extraAnnotations.IsDefault) { return(NullableTypeDecoder.TransformType(metadataType, targetSymbolToken, containingModule, nonNullTypesContext)); } else { return(NullableTypeDecoder.TransformType(metadataType, extraAnnotations, NonNullTypesTrueContext.Instance)); } }
internal static NamespaceOrTypeOrAliasSymbolWithAnnotations CreateUnannotated(INonNullTypesContext nonNullTypesContext, Symbol symbol) { if (symbol is null) { return(default);
internal override bool ApplyNullableTransforms(ImmutableArray <bool> transforms, INonNullTypesContext nonNullTypesContext, ref int position, out TypeSymbol result) { TypeSymbolWithAnnotations oldElementType = ElementType; TypeSymbolWithAnnotations newElementType; if (!oldElementType.ApplyNullableTransforms(transforms, nonNullTypesContext, ref position, out newElementType)) { result = this; return(false); } result = WithElementType(newElementType); return(true); }
/// <param name="sourceType">Type that already has custom modifiers.</param> /// <param name="destinationType">Same as <paramref name="sourceType"/>, but without custom modifiers. May differ in object/dynamic.</param> /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param> /// <param name="nonNullTypesContext">The NonNullTypes context at the destination.</param> /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns> internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, AssemblySymbol containingAssembly, INonNullTypesContext nonNullTypesContext) { Debug.Assert(sourceType.Equals(destinationType, TypeCompareKind.AllIgnoreOptions)); Debug.Assert(nonNullTypesContext != null); const RefKind refKind = RefKind.None; // NOTE: overrides can differ by object/dynamic. If they do, we'll need to tweak newType before // we can use it in place of this.Type. We do so by computing the dynamic transform flags that // code gen uses and then passing them to the dynamic type decoder that metadata reading uses. // NOTE: ref is irrelevant here since we are just encoding/decoding the type out of the signature context ImmutableArray <bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind); TypeSymbol typeWithDynamic = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags); TypeSymbol resultType; if (destinationType.ContainsTuple() && !sourceType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreDynamic)) { // We also preserve tuple names, if present and different ImmutableArray <string> names = CSharpCompilation.TupleNamesEncoder.Encode(destinationType); resultType = TupleTypeDecoder.DecodeTupleTypesIfApplicable(typeWithDynamic, names); } else { resultType = typeWithDynamic; } // Preserve nullable modifiers as well. // https://github.com/dotnet/roslyn/issues/30077: Is it reasonable to copy annotations from the source? // If the destination had some of those annotations but not all, then clearly the destination // was incorrect. Or if the destination is C#7, then the destination will advertise annotations // that the author did not write and did not validate. var flagsBuilder = ArrayBuilder <bool> .GetInstance(); destinationType.AddNullableTransforms(flagsBuilder); int position = 0; int length = flagsBuilder.Count; bool transformResult = resultType.ApplyNullableTransforms(flagsBuilder.ToImmutableAndFree(), nonNullTypesContext, ref position, out resultType); Debug.Assert(transformResult && position == length); Debug.Assert(resultType.Equals(sourceType, TypeCompareKind.IgnoreDynamicAndTupleNames)); // Same custom modifiers as source type. // Note: We would want to check nullability, but that would pull on NonNullTypes too early (ie. cause cycles). Debug.Assert(resultType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)); // Same object/dynamic and tuple names as destination type. return(resultType); }
private TypeMap WithAlphaRename(ImmutableArray <TypeParameterSymbol> oldTypeParameters, Symbol newOwner, INonNullTypesContext nonNullTypesContext, out ImmutableArray <TypeParameterSymbol> newTypeParameters) { if (oldTypeParameters.Length == 0) { newTypeParameters = ImmutableArray <TypeParameterSymbol> .Empty; return(this); } // Note: the below assertion doesn't hold while rewriting async lambdas defined inside generic methods. // The async rewriter adds a synthesized struct inside the lambda frame and construct a typemap from // the lambda frame's substituted type parameters. // Debug.Assert(!oldTypeParameters.Any(tp => tp is SubstitutedTypeParameterSymbol)); // warning: we expose result to the SubstitutedTypeParameterSymbol constructor, below, even before it's all filled in. TypeMap result = new TypeMap(this.Mapping); ArrayBuilder <TypeParameterSymbol> newTypeParametersBuilder = ArrayBuilder <TypeParameterSymbol> .GetInstance(); // The case where it is "synthesized" is when we're creating type parameters for a synthesized (generic) // class or method for a lambda appearing in a generic method. bool synthesized = !ReferenceEquals(oldTypeParameters[0].ContainingSymbol.OriginalDefinition, newOwner.OriginalDefinition); int ordinal = 0; foreach (var tp in oldTypeParameters) { var newTp = synthesized ? new SynthesizedSubstitutedTypeParameterSymbol(newOwner, result, tp, ordinal) : new SubstitutedTypeParameterSymbol(newOwner, result, tp, ordinal); result.Mapping.Add(tp, TypeSymbolWithAnnotations.Create(nonNullTypesContext, newTp)); newTypeParametersBuilder.Add(newTp); ordinal++; } newTypeParameters = newTypeParametersBuilder.ToImmutableAndFree(); return(result); }
internal override bool ApplyNullableTransforms(ImmutableArray <bool> transforms, INonNullTypesContext nonNullTypesContext, ref int position, out TypeSymbol result) { result = this; return(true); }
internal static ImmutableArray <TypeSymbolWithAnnotations> TypeParametersAsTypeSymbolsWithAnnotations(INonNullTypesContext nonNullTypesContext, ImmutableArray <TypeParameterSymbol> typeParameters) { return(typeParameters.SelectAsArray((tp, c) => TypeSymbolWithAnnotations.Create(nonNullTypesContext: c, tp, isAnnotated: false, customModifiers: ImmutableArray <CustomModifier> .Empty), nonNullTypesContext)); }
// Only when the caller passes allowAlpha=true do we tolerate substituted (alpha-renamed) type parameters as keys internal TypeMap(INonNullTypesContext nonNullTypesContext, ImmutableArray <TypeParameterSymbol> from, ImmutableArray <TypeParameterSymbol> to, bool allowAlpha = false) : this(from, TypeParametersAsTypeSymbolsWithAnnotations(nonNullTypesContext, to), allowAlpha) { // mapping contents are read-only hereafter }
internal TypeMap WithAlphaRename(MethodSymbol oldOwner, Symbol newOwner, INonNullTypesContext nonNullTypesContext, out ImmutableArray <TypeParameterSymbol> newTypeParameters) { Debug.Assert(oldOwner.ConstructedFrom == oldOwner); return(WithAlphaRename(oldOwner.OriginalDefinition.TypeParameters, newOwner, nonNullTypesContext, out newTypeParameters)); }
internal override bool ApplyNullableTransforms(ImmutableArray <bool> transforms, INonNullTypesContext nonNullTypesContext, ref int position, out TypeSymbol result) { TypeSymbolWithAnnotations oldElementType = ElementType; TypeSymbolWithAnnotations newElementType; if (!oldElementType.ApplyNullableTransforms(transforms, nonNullTypesContext, ref position, out newElementType)) { result = this; return(false); } if (oldElementType.IsSameAs(newElementType)) { result = this; } else { result = IsSZArray ? ArrayTypeSymbol.CreateSZArray(newElementType, _baseType) : ArrayTypeSymbol.CreateMDArray(newElementType, Rank, Sizes, LowerBounds, _baseType); } return(true); }
internal ImmutableArray <TypeSymbolWithAnnotations> GetTypeParametersAsTypeArguments(INonNullTypesContext nonNullTypesContext) => TypeMap.TypeParametersAsTypeSymbolsWithAnnotations(nonNullTypesContext, TypeParameters);
internal override bool ApplyNullableTransforms(ImmutableArray <bool> transforms, INonNullTypesContext nonNullTypesContext, ref int position, out TypeSymbol result) { TypeSymbolWithAnnotations oldPointedAtType = PointedAtType; TypeSymbolWithAnnotations newPointedAtType; if (!oldPointedAtType.ApplyNullableTransforms(transforms, nonNullTypesContext, ref position, out newPointedAtType)) { result = this; return(false); } if (oldPointedAtType.IsSameAs(newPointedAtType)) { result = this; } else { result = new PointerTypeSymbol(newPointedAtType); } return(true); }
internal static TypeSymbolWithAnnotations TransformType(TypeSymbolWithAnnotations metadataType, ImmutableArray <bool> nullableTransformFlags, INonNullTypesContext nonNullTypesContext) { int position = 0; TypeSymbolWithAnnotations result; if (metadataType.ApplyNullableTransforms(nullableTransformFlags, nonNullTypesContext, ref position, out result) && (nullableTransformFlags.IsDefault || position == nullableTransformFlags.Length)) { return(result); } // No NullableAttribute applied to the target symbol, or flags do not line-up, return unchanged metadataType. return(metadataType); }
internal LazyMissingNonNullTypesContextForSuppressionDiagnosticInfo(INonNullTypesContext context) { _context = context; }
private static DiagnosticInfo ReportNullableReferenceTypesIfNeeded(CSharpCompilation compilation, INonNullTypesContext nonNullTypesContext) { var featureID = MessageID.IDS_FeatureNullableReferenceTypes; if (!compilation.IsFeatureEnabled(featureID)) { LanguageVersion availableVersion = compilation.LanguageVersion; LanguageVersion requiredVersion = featureID.RequiredVersion(); return(new CSDiagnosticInfo(availableVersion.GetErrorCode(), featureID.Localize(), new CSharpRequiredLanguageVersion(requiredVersion))); } else if (nonNullTypesContext.NonNullTypes != true) { return(new CSDiagnosticInfo(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation)); } return(null); }
/// <summary> /// A `?` annotation on a type that isn't a value type causes: /// - an error before C# 8.0 /// - a warning outside of a NonNullTypes context /// </summary> public static DiagnosticInfo ReportNullableReferenceTypesIfNeeded(CSharpCompilation compilation, INonNullTypesContext context, TypeSymbolWithAnnotations type) { return(!type.IsNull && (type.IsValueType || type.IsErrorType()) ? null : ReportNullableReferenceTypesIfNeeded(compilation, context)); }
internal LazyMissingNonNullTypesContextDiagnosticInfo(CSharpCompilation compilation, INonNullTypesContext context, TypeSymbolWithAnnotations type) { _compilation = compilation; _context = context; _type = type; }