/// <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="refKind"><see cref="RefKind"/> of the parameter of which this is the type (or <see cref="RefKind.None"/> for a return type.</param> /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param> /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns> internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, RefKind refKind, AssemblySymbol containingAssembly) { Debug.Assert(sourceType.Equals(destinationType, TypeCompareKind.AllIgnoreOptions)); // 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. 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, containingAssembly, names); } else { resultType = typeWithDynamic; } Debug.Assert(resultType.Equals(sourceType, TypeCompareKind.IgnoreDynamicAndTupleNames)); // Same custom modifiers as source type. Debug.Assert(resultType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)); // Same object/dynamic and tuple names as destination type. return(resultType); }
/// <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="refKind"><see cref="RefKind"/> of the parameter of which this is the type (or <see cref="RefKind.None"/> for a return type.</param> /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param> /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns> internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, RefKind refKind, AssemblySymbol containingAssembly) { Debug.Assert(sourceType.Equals(destinationType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true)); if (sourceType.ContainsTuple()) { // TODO(https://github.com/dotnet/roslyn/issues/12389): // Need to save/restore tupleness as well if (sourceType.IsTupleType) { Debug.Assert(destinationType.IsTupleType); return destinationType; } ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind); TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags); Debug.Assert(resultType.Equals(sourceType, ignoreCustomModifiersAndArraySizesAndLowerBounds: false, ignoreDynamic: true)); // Same custom modifiers as source type. return resultType; } else { // 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. ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind); TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags); Debug.Assert(resultType.Equals(sourceType, ignoreCustomModifiersAndArraySizesAndLowerBounds: false, ignoreDynamic: true)); // Same custom modifiers as source type. Debug.Assert(resultType.Equals(destinationType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: false)); // Same object/dynamic as destination type. return resultType; } }
/// <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="refKind"><see cref="RefKind"/> of the parameter of which this is the type (or <see cref="RefKind.None"/> for a return type.</param> /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param> /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns> internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, RefKind refKind, AssemblySymbol containingAssembly) { Debug.Assert(sourceType.Equals(destinationType, TypeCompareKind.AllIgnoreOptions)); // 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. 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, containingAssembly, names); } else { resultType = typeWithDynamic; } Debug.Assert(resultType.Equals(sourceType, TypeCompareKind.IgnoreDynamicAndTupleNames)); // Same custom modifiers as source type. Debug.Assert(resultType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)); // Same object/dynamic and tuple names as destination type. return resultType; }
/// <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); }
internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, AssemblySymbol containingAssembly) { Debug.Assert(sourceType.Equals(destinationType, TypeCompareKind.AllIgnoreOptions)); const RefKind refKind = RefKind.None; // NOTE: overrides can differ by object/dynamic, tuple element names, etc. // If they do, we'll need to tweak destinationType before we can use it in place of sourceType. // NOTE: refKind is irrelevant here since we are just encoding/decoding the type. ImmutableArray <bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind); TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags); if (!containingAssembly.RuntimeSupportsNumericIntPtr) { var builder = ArrayBuilder <bool> .GetInstance(); CSharpCompilation.NativeIntegerTransformsEncoder.Encode(builder, destinationType); resultType = NativeIntegerTypeDecoder.TransformType(resultType, builder.ToImmutableAndFree()); } if (destinationType.ContainsTuple() && !sourceType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes | TypeCompareKind.IgnoreDynamic)) { // We also preserve tuple names, if present and different ImmutableArray <string> names = CSharpCompilation.TupleNamesEncoder.Encode(destinationType); resultType = TupleTypeDecoder.DecodeTupleTypesIfApplicable(resultType, names); } // 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 <byte> .GetInstance(); destinationType.AddNullableTransforms(flagsBuilder); int position = 0; int length = flagsBuilder.Count; bool transformResult = resultType.ApplyNullableTransforms(defaultTransformFlag: 0, flagsBuilder.ToImmutableAndFree(), ref position, out resultType); Debug.Assert(transformResult && position == length); Debug.Assert(resultType.Equals(sourceType, TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes | TypeCompareKind.IgnoreNativeIntegers)); // Same custom modifiers as source type. // Same object/dynamic, nullability, native integers, and tuple names as destination type. Debug.Assert(resultType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)); return(resultType); }
internal SynthesizedAttributeData SynthesizeTupleNamesAttribute(TypeSymbol type) { Debug.Assert((object)type != null); Debug.Assert(type.ContainsTuple()); var stringType = GetSpecialType(SpecialType.System_String); Debug.Assert((object)stringType != null); var names = TupleNamesEncoder.Encode(type, stringType); Debug.Assert(!names.IsDefault, "should not need the attribute when no tuple names"); var stringArray = ArrayTypeSymbol.CreateSZArray(stringType.ContainingAssembly, stringType, customModifiers: ImmutableArray <CustomModifier> .Empty); var args = ImmutableArray.Create(new TypedConstant(stringArray, names)); return(TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_TupleElementNamesAttribute__ctorTransformNames, args)); }
/// <summary> /// Returns first or a modified version of first with common tuple names from both types. /// </summary> internal static TypeSymbol MergeTupleNames(TypeSymbol first, TypeSymbol second) { if (first.Equals(second, TypeCompareKind.AllIgnoreOptions & ~TypeCompareKind.IgnoreTupleNames) || !first.ContainsTupleNames()) { return first; } Debug.Assert(first.ContainsTuple()); ImmutableArray<string> names1 = CSharpCompilation.TupleNamesEncoder.Encode(first); ImmutableArray<string> names2 = CSharpCompilation.TupleNamesEncoder.Encode(second); ImmutableArray<string> mergedNames; if (names1.IsDefault || names2.IsDefault) { mergedNames = default(ImmutableArray<string>); } else { Debug.Assert(names1.Length == names2.Length); mergedNames = names1.ZipAsArray(names2, (n1, n2) => string.CompareOrdinal(n1, n2) == 0 ? n1 : null); if (mergedNames.All(n => n == null)) { mergedNames = default(ImmutableArray<string>); } } return TupleTypeDecoder.DecodeTupleTypesIfApplicable(first, mergedNames); }
/// <summary> /// Takes the names from the two types, finds the common names, and applies them onto the target. /// </summary> internal static TypeSymbol MergeTupleNames(TypeSymbol first, TypeSymbol second, TypeSymbol target, AssemblySymbol corLibrary) { if (!target.ContainsTuple() || first.Equals(second, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreDynamic) || !target.ContainsTupleNames()) { return target; } ImmutableArray<string> names1 = CSharpCompilation.TupleNamesEncoder.Encode(first); ImmutableArray<string> names2 = CSharpCompilation.TupleNamesEncoder.Encode(second); ImmutableArray<string> mergedNames; if (names1.IsDefault || names2.IsDefault) { mergedNames = default(ImmutableArray<string>); } else { Debug.Assert(names1.Length == names2.Length); mergedNames = names1.ZipAsArray(names2, (n1, n2) => string.CompareOrdinal(n1, n2) == 0 ? n1 : null); if (mergedNames.All(n => n == null)) { mergedNames = default(ImmutableArray<string>); } } return TupleTypeDecoder.DecodeTupleTypesIfApplicable(target, corLibrary, mergedNames); }