提交 238db4f7 编写于 作者: A AlekseyTs

Add support for custom modifiers referencing generic types.

Fixes #5725.
上级 a4e375b9
...@@ -15,7 +15,6 @@ bool Cci.ICustomModifier.IsOptional ...@@ -15,7 +15,6 @@ bool Cci.ICustomModifier.IsOptional
Cci.ITypeReference Cci.ICustomModifier.GetModifier(EmitContext context) Cci.ITypeReference Cci.ICustomModifier.GetModifier(EmitContext context)
{ {
Debug.Assert(this.Modifier.IsDefinition);
return ((PEModuleBuilder)context.Module).Translate(this.Modifier, (CSharpSyntaxNode)context.SyntaxNodeOpt, context.Diagnostics); return ((PEModuleBuilder)context.Module).Translate(this.Modifier, (CSharpSyntaxNode)context.SyntaxNodeOpt, context.Diagnostics);
} }
} }
......
...@@ -145,9 +145,50 @@ internal ImmutableArray<CustomModifier> SubstituteCustomModifiers(TypeSymbol typ ...@@ -145,9 +145,50 @@ internal ImmutableArray<CustomModifier> SubstituteCustomModifiers(TypeSymbol typ
return new TypeWithModifiers(type, customModifiers).SubstituteType(this).CustomModifiers; return new TypeWithModifiers(type, customModifiers).SubstituteType(this).CustomModifiers;
} }
return customModifiers; return SubstituteCustomModifiers(customModifiers);
} }
internal ImmutableArray<CustomModifier> SubstituteCustomModifiers(ImmutableArray<CustomModifier> customModifiers)
{
if (customModifiers.IsDefaultOrEmpty)
{
return customModifiers;
}
for (int i = 0; i < customModifiers.Length; i++)
{
var modifier = (NamedTypeSymbol)customModifiers[i].Modifier;
var substituted = SubstituteNamedType(modifier);
if (modifier != substituted)
{
var builder = ArrayBuilder<CustomModifier>.GetInstance(customModifiers.Length);
builder.AddRange(customModifiers, i);
builder.Add(customModifiers[i].IsOptional ? CSharpCustomModifier.CreateOptional(substituted) : CSharpCustomModifier.CreateRequired(substituted));
for (i++; i < customModifiers.Length; i++)
{
modifier = (NamedTypeSymbol)customModifiers[i].Modifier;
substituted = SubstituteNamedType(modifier);
if (modifier != substituted)
{
builder.Add(customModifiers[i].IsOptional ? CSharpCustomModifier.CreateOptional(substituted) : CSharpCustomModifier.CreateRequired(substituted));
}
else
{
builder.Add(customModifiers[i]);
}
}
Debug.Assert(builder.Count == customModifiers.Length);
return builder.ToImmutableAndFree();
}
}
return customModifiers;
}
protected virtual TypeSymbol SubstituteDynamicType() protected virtual TypeSymbol SubstituteDynamicType()
{ {
return DynamicTypeSymbol.Instance; return DynamicTypeSymbol.Instance;
......
...@@ -934,7 +934,15 @@ internal bool DeriveUseSiteDiagnosticFromCustomModifiers(ref DiagnosticInfo resu ...@@ -934,7 +934,15 @@ internal bool DeriveUseSiteDiagnosticFromCustomModifiers(ref DiagnosticInfo resu
{ {
foreach (CustomModifier modifier in customModifiers) foreach (CustomModifier modifier in customModifiers)
{ {
if (DeriveUseSiteDiagnosticFromType(ref result, (TypeSymbol)modifier.Modifier)) var modifierType = (NamedTypeSymbol)modifier.Modifier;
// Unbound generic type is valid as a modifier, let's not report any use site diagnostics because of that.
if (modifierType.IsUnboundGenericType )
{
modifierType = modifierType.OriginalDefinition;
}
if (DeriveUseSiteDiagnosticFromType(ref result, modifierType))
{ {
return true; return true;
} }
......
...@@ -86,14 +86,15 @@ public TypeSymbol AsTypeSymbolOnly() ...@@ -86,14 +86,15 @@ public TypeSymbol AsTypeSymbolOnly()
public TypeWithModifiers SubstituteType(AbstractTypeMap typeMap) public TypeWithModifiers SubstituteType(AbstractTypeMap typeMap)
{ {
var newCustomModifiers = typeMap.SubstituteCustomModifiers(this.CustomModifiers);
var newTypeWithModifiers = typeMap.SubstituteType(this.Type); var newTypeWithModifiers = typeMap.SubstituteType(this.Type);
if (!newTypeWithModifiers.Is(this.Type)) if (!newTypeWithModifiers.Is(this.Type) || newCustomModifiers != this.CustomModifiers)
{ {
return new TypeWithModifiers(newTypeWithModifiers.Type, this.CustomModifiers.Concat(newTypeWithModifiers.CustomModifiers)); return new TypeWithModifiers(newTypeWithModifiers.Type, newCustomModifiers.Concat(newTypeWithModifiers.CustomModifiers));
} }
else else
{ {
return this; // substitution had no effect on the type return this; // substitution had no effect on the type or modifiers
} }
} }
} }
......
...@@ -1370,5 +1370,214 @@ public override void Test(int [,] c) ...@@ -1370,5 +1370,214 @@ public override void Test(int [,] c)
CompileAndVerify(compilation, expectedOutput: @"Test CompileAndVerify(compilation, expectedOutput: @"Test
Overriden"); Overriden");
} }
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")]
public void ModifiersWithConstructedType_01()
{
var ilSource = @"
.class public auto ansi beforefieldinit CL1`1<valuetype .ctor ([mscorlib]System.ValueType) T1>
extends[mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006:
ret
} // end of method CL1`1::.ctor
.method public hidebysig newslot virtual
instance void Test(!T1 modopt(valuetype [mscorlib]System.Nullable`1<!T1>) t1) cil managed
{
// Code size 1 (0x1)
.maxstack 1
IL_0000: ldstr ""Test""
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method CL1`1::Test
} // end of class CL1`1
.class public auto ansi beforefieldinit CL2
extends class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>::.ctor()
IL_0006: ret
} // end of method CL2::.ctor
} // end of class CL2
";
var source = @"
class Test
{
static void Main()
{
var x = new CL2();
x.Test(1);
x = new CL3();
x.Test(1);
}
}
class CL3 : CL2
{
public override void Test(int c)
{
System.Console.WriteLine(""Overriden"");
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: @"Test
Overriden");
}
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")]
public void ModifiersWithConstructedType_02()
{
var ilSource = @"
.class public auto ansi beforefieldinit CL1`1<valuetype .ctor ([mscorlib]System.ValueType) T1>
extends[mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006:
ret
} // end of method CL1`1::.ctor
.method public hidebysig newslot virtual
instance void Test(!T1 modopt(valuetype [mscorlib]System.Nullable`1) t1) cil managed
{
// Code size 1 (0x1)
.maxstack 1
IL_0000: ldstr ""Test""
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method CL1`1::Test
} // end of class CL1`1
.class public auto ansi beforefieldinit CL2
extends class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>::.ctor()
IL_0006: ret
} // end of method CL2::.ctor
} // end of class CL2
";
var source = @"
class Test
{
static void Main()
{
var x = new CL2();
x.Test(1);
x = new CL3();
x.Test(1);
}
}
class CL3 : CL2
{
public override void Test(int c)
{
System.Console.WriteLine(""Overriden"");
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: @"Test
Overriden");
}
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")]
public void ModifiersWithConstructedType_03()
{
var ilSource = @"
.class public auto ansi beforefieldinit CL1`1<valuetype .ctor ([mscorlib]System.ValueType) T1>
extends[mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006:
ret
} // end of method CL1`1::.ctor
.method public hidebysig newslot virtual
instance int32 modopt(CL2) modopt(valuetype [mscorlib]System.Nullable`1<!T1>) modopt(valuetype [mscorlib]System.Nullable`1<!T1>) modopt(CL2) [] Test(!T1 t1) cil managed
{
// Code size 1 (0x1)
.maxstack 1
IL_0000: ldstr ""Test""
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_0006: ldnull
IL_000a: ret
} // end of method CL1`1::Test
} // end of class CL1`1
.class public auto ansi beforefieldinit CL2
extends class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>::.ctor()
IL_0006: ret
} // end of method CL2::.ctor
} // end of class CL2
";
var source = @"
class Test
{
static void Main()
{
var x = new CL2();
x.Test(1);
x = new CL3();
x.Test(1);
}
}
class CL3 : CL2
{
public override int[] Test(int c)
{
System.Console.WriteLine(""Overriden"");
return null;
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: @"Test
Overriden");
}
} }
} }
\ No newline at end of file
...@@ -309,56 +309,63 @@ private TypeSymbol DecodeTypeOrThrow(ref BlobReader ppSig, SignatureTypeCode typ ...@@ -309,56 +309,63 @@ private TypeSymbol DecodeTypeOrThrow(ref BlobReader ppSig, SignatureTypeCode typ
break; break;
case SignatureTypeCode.GenericTypeInstance: case SignatureTypeCode.GenericTypeInstance:
SignatureTypeCode elementTypeCode = ppSig.ReadSignatureTypeCode(); typeSymbol = DecodeGenericTypeInstanceOrThrow(ref ppSig, out refersToNoPiaLocalType);
if (elementTypeCode != SignatureTypeCode.TypeHandle) break;
{
throw new UnsupportedSignatureContent();
}
EntityHandle tokenGeneric = ppSig.ReadTypeHandle(); default:
int argumentCount; throw new UnsupportedSignatureContent();
if (!ppSig.TryReadCompressedInteger(out argumentCount)) }
{
throw new UnsupportedSignatureContent();
}
TypeSymbol generic = GetTypeOfToken(tokenGeneric, out refersToNoPiaLocalType); return typeSymbol;
Debug.Assert(!refersToNoPiaLocalType || generic.TypeKind == TypeKind.Error); }
var argumentsBuilder = ArrayBuilder<KeyValuePair<TypeSymbol, ImmutableArray<ModifierInfo<TypeSymbol>>>>.GetInstance(argumentCount); private TypeSymbol DecodeGenericTypeInstanceOrThrow(ref BlobReader ppSig, out bool refersToNoPiaLocalType)
var argumentRefersToNoPiaLocalTypeBuilder = ArrayBuilder<bool>.GetInstance(argumentCount); {
SignatureTypeCode elementTypeCode = ppSig.ReadSignatureTypeCode();
if (elementTypeCode != SignatureTypeCode.TypeHandle)
{
throw new UnsupportedSignatureContent();
}
for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) EntityHandle tokenGeneric = ppSig.ReadTypeHandle();
{ int argumentCount;
bool argumentRefersToNoPia; if (!ppSig.TryReadCompressedInteger(out argumentCount))
modifiers = DecodeModifiersOrThrow(ref ppSig, out typeCode); {
argumentsBuilder.Add(KeyValuePair.Create(DecodeTypeOrThrow(ref ppSig, typeCode, out argumentRefersToNoPia), modifiers)); throw new UnsupportedSignatureContent();
argumentRefersToNoPiaLocalTypeBuilder.Add(argumentRefersToNoPia); }
}
// The instantiated type might have a generic parent, in which case some or all of the type TypeSymbol generic = GetTypeOfToken(tokenGeneric, out refersToNoPiaLocalType);
// arguments might actually be for the parent. Debug.Assert(!refersToNoPiaLocalType || generic.TypeKind == TypeKind.Error);
var arguments = argumentsBuilder.ToImmutableAndFree(); var argumentsBuilder = ArrayBuilder<KeyValuePair<TypeSymbol, ImmutableArray<ModifierInfo<TypeSymbol>>>>.GetInstance(argumentCount);
var argumentRefersToNoPiaLocalType = argumentRefersToNoPiaLocalTypeBuilder.ToImmutableAndFree(); var argumentRefersToNoPiaLocalTypeBuilder = ArrayBuilder<bool>.GetInstance(argumentCount);
typeSymbol = SubstituteTypeParameters(generic, arguments, argumentRefersToNoPiaLocalType);
foreach (bool flag in argumentRefersToNoPiaLocalType) for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++)
{ {
if (flag) bool argumentRefersToNoPia;
{ SignatureTypeCode typeCode;
refersToNoPiaLocalType = true; ImmutableArray<ModifierInfo<TypeSymbol>> modifiers = DecodeModifiersOrThrow(ref ppSig, out typeCode);
break; argumentsBuilder.Add(KeyValuePair.Create(DecodeTypeOrThrow(ref ppSig, typeCode, out argumentRefersToNoPia), modifiers));
} argumentRefersToNoPiaLocalTypeBuilder.Add(argumentRefersToNoPia);
} }
break; // The instantiated type might have a generic parent, in which case some or all of the type
// arguments might actually be for the parent.
default: var arguments = argumentsBuilder.ToImmutableAndFree();
throw new UnsupportedSignatureContent(); var argumentRefersToNoPiaLocalType = argumentRefersToNoPiaLocalTypeBuilder.ToImmutableAndFree();
TypeSymbol typeSymbol = SubstituteTypeParameters(generic, arguments, argumentRefersToNoPiaLocalType);
foreach (bool flag in argumentRefersToNoPiaLocalType)
{
if (flag)
{
refersToNoPiaLocalType = true;
break;
}
} }
return typeSymbol; return typeSymbol;
} }
/// <exception cref="UnsupportedSignatureContent">If the encoded type is invalid.</exception> /// <exception cref="UnsupportedSignatureContent">If the encoded type is invalid.</exception>
...@@ -653,13 +660,7 @@ private ImmutableArray<ModifierInfo<TypeSymbol>> DecodeModifiersOrThrow(ref Blob ...@@ -653,13 +660,7 @@ private ImmutableArray<ModifierInfo<TypeSymbol>> DecodeModifiersOrThrow(ref Blob
if (typeCode == SignatureTypeCode.OptionalModifier) if (typeCode == SignatureTypeCode.OptionalModifier)
{ {
EntityHandle token = signatureReader.ReadTypeHandle(); ModifierInfo<TypeSymbol> modifier = new ModifierInfo<TypeSymbol>(true, DecodeModifierTypeOrThrow(ref signatureReader));
ModifierInfo<TypeSymbol> modifier = new ModifierInfo<TypeSymbol>(true, GetTypeOfToken(token));
if (!IsAcceptableModOptModifier(token, modifier.Modifier))
{
throw new UnsupportedSignatureContent();
}
if (modifiers == null) if (modifiers == null)
{ {
...@@ -676,48 +677,83 @@ private ImmutableArray<ModifierInfo<TypeSymbol>> DecodeModifiersOrThrow(ref Blob ...@@ -676,48 +677,83 @@ private ImmutableArray<ModifierInfo<TypeSymbol>> DecodeModifiersOrThrow(ref Blob
return modifiers?.ToImmutableAndFree() ?? default(ImmutableArray<ModifierInfo<TypeSymbol>>); return modifiers?.ToImmutableAndFree() ?? default(ImmutableArray<ModifierInfo<TypeSymbol>>);
} }
/// <summary> private TypeSymbol DecodeModifierTypeOrThrow(ref BlobReader signatureReader)
/// According to ECMA spec:
/// The CMOD_OPT or CMOD_REQD is followed by a metadata token that
/// indexes a row in the TypeDef table or the TypeRef table.
/// i.e. No modopt in DecodeType (though it still works in DecodeModifier).
/// </summary>
private static bool IsAcceptableModOptModifier(EntityHandle token, TypeSymbol modifier)
{ {
EntityHandle token = signatureReader.ReadTypeHandle();
TypeSymbol type;
bool isNoPiaLocalType;
// According to ECMA spec:
// The CMOD_OPT or CMOD_REQD is followed by a metadata token that
// indexes a row in the TypeDef table or the TypeRef table.
tryAgain:
switch (token.Kind) switch (token.Kind)
{ {
case HandleKind.TypeDefinition: case HandleKind.TypeDefinition:
type = GetTypeOfTypeDef((TypeDefinitionHandle)token, out isNoPiaLocalType, isContainingType: false);
// it is valid for a modifier to refer to an unconstructed type, we need to preserve this fact
type = SubstituteWithUnboundIfGeneric(type);
break;
case HandleKind.TypeReference: case HandleKind.TypeReference:
return true; type = GetTypeOfTypeRef((TypeReferenceHandle)token, out isNoPiaLocalType);
// it is valid for a modifier to refer to an unconstructed type, we need to preserve this fact
type = SubstituteWithUnboundIfGeneric(type);
break;
case HandleKind.TypeSpecification: case HandleKind.TypeSpecification:
// Section 23.2.7 of the CLI spec specifically says that this is not allowed (see comment on method), // Section 23.2.7 of the CLI spec specifically says that this is not allowed (see comment on method),
// but, apparently, ilasm turns modopt(int32) into a TypeSpec. // but, apparently, ilasm turns modopt(int32) into a TypeSpec.
if (modifier != null) // In addition, managed C++ compiler can use constructed generic types as modifiers, for example Nullable<bool>, etc.
// We will support only cases like these even though it looks like CLR allows any types that can be encoded through a TypeSpec.
BlobReader memoryReader = this.Module.GetTypeSpecificationSignatureReaderOrThrow((TypeSpecificationHandle)token);
SignatureTypeCode typeCode = memoryReader.ReadSignatureTypeCode();
bool refersToNoPiaLocalType;
switch (typeCode)
{ {
switch (modifier.SpecialType) case SignatureTypeCode.Void:
{ case SignatureTypeCode.Boolean:
case SpecialType.System_Void: case SignatureTypeCode.SByte:
case SpecialType.System_Boolean: case SignatureTypeCode.Byte:
case SpecialType.System_SByte: case SignatureTypeCode.Int16:
case SpecialType.System_Byte: case SignatureTypeCode.UInt16:
case SpecialType.System_Int16: case SignatureTypeCode.Int32:
case SpecialType.System_UInt16: case SignatureTypeCode.UInt32:
case SpecialType.System_Int32: case SignatureTypeCode.Int64:
case SpecialType.System_UInt32: case SignatureTypeCode.UInt64:
case SpecialType.System_Int64: case SignatureTypeCode.Single:
case SpecialType.System_UInt64: case SignatureTypeCode.Double:
case SpecialType.System_Single: case SignatureTypeCode.Char:
case SpecialType.System_Double: case SignatureTypeCode.String:
case SpecialType.System_Char: case SignatureTypeCode.IntPtr:
case SpecialType.System_String: case SignatureTypeCode.UIntPtr:
case SpecialType.System_Object: case SignatureTypeCode.Object:
return true; case SignatureTypeCode.TypedReference:
} type = GetSpecialType(typeCode.ToSpecialType());
break;
case SignatureTypeCode.TypeHandle:
token = memoryReader.ReadTypeHandle();
goto tryAgain;
case SignatureTypeCode.GenericTypeInstance:
type = DecodeGenericTypeInstanceOrThrow(ref memoryReader, out refersToNoPiaLocalType);
break;
default:
throw new UnsupportedSignatureContent();
} }
return false; break;
default: default:
return false; throw new UnsupportedSignatureContent();
} }
return type;
} }
/// <exception cref="UnsupportedSignatureContent">If the encoded local variable type is invalid.</exception> /// <exception cref="UnsupportedSignatureContent">If the encoded local variable type is invalid.</exception>
...@@ -1645,14 +1681,23 @@ protected TypeSymbol DecodeFieldSignature(ref BlobReader signatureReader, out bo ...@@ -1645,14 +1681,23 @@ protected TypeSymbol DecodeFieldSignature(ref BlobReader signatureReader, out bo
if (typeCode == SignatureTypeCode.OptionalModifier || if (typeCode == SignatureTypeCode.OptionalModifier ||
typeCode == SignatureTypeCode.RequiredModifier) typeCode == SignatureTypeCode.RequiredModifier)
{ {
EntityHandle token = signatureReader.ReadTypeHandle(); TypeSymbol type;
ModifierInfo<TypeSymbol> modifier = new ModifierInfo<TypeSymbol>((typeCode == SignatureTypeCode.OptionalModifier), GetTypeOfToken(token));
if (!IsAcceptableModOptModifier(token, modifier.Modifier)) try
{
type = DecodeModifierTypeOrThrow(ref signatureReader);
}
catch (BadImageFormatException mrEx)
{
return GetUnsupportedMetadataTypeSymbol(mrEx); // an exception from metadata reader.
}
catch (UnsupportedSignatureContent)
{ {
return GetUnsupportedMetadataTypeSymbol(); // unsupported signature content return GetUnsupportedMetadataTypeSymbol(); // unsupported signature content
} }
ModifierInfo<TypeSymbol> modifier = new ModifierInfo<TypeSymbol>((typeCode == SignatureTypeCode.OptionalModifier), type);
if (IsVolatileModifierType(modifier.Modifier)) if (IsVolatileModifierType(modifier.Modifier))
{ {
isVolatile = true; isVolatile = true;
......
...@@ -15,7 +15,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ...@@ -15,7 +15,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Property End Property
Private Function CciGetModifier(context As EmitContext) As Cci.ITypeReference Implements Cci.ICustomModifier.GetModifier Private Function CciGetModifier(context As EmitContext) As Cci.ITypeReference Implements Cci.ICustomModifier.GetModifier
Debug.Assert(Me.Modifier Is Me.Modifier.OriginalDefinition)
Return DirectCast(context.Module, PEModuleBuilder).Translate(Me.Modifier, DirectCast(context.SyntaxNodeOpt, VisualBasicSyntaxNode), context.Diagnostics) Return DirectCast(context.Module, PEModuleBuilder).Translate(Me.Modifier, DirectCast(context.SyntaxNodeOpt, VisualBasicSyntaxNode), context.Diagnostics)
End Function End Function
End Class End Class
......
...@@ -866,6 +866,40 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ...@@ -866,6 +866,40 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return New TypeWithModifiers(type, customModifiers).InternalSubstituteTypeParameters(Me).CustomModifiers Return New TypeWithModifiers(type, customModifiers).InternalSubstituteTypeParameters(Me).CustomModifiers
End If End If
Return SubstituteCustomModifiers(customModifiers)
End Function
Function SubstituteCustomModifiers(customModifiers As ImmutableArray(Of CustomModifier)) As ImmutableArray(Of CustomModifier)
If customModifiers.IsDefaultOrEmpty Then
Return customModifiers
End If
For i As Integer = 0 To customModifiers.Length - 1
Dim modifier = DirectCast(customModifiers(i).Modifier, NamedTypeSymbol)
Dim substituted = DirectCast(modifier.InternalSubstituteTypeParameters(Me).AsTypeSymbolOnly(), NamedTypeSymbol)
If modifier <> substituted Then
Dim builder = ArrayBuilder(Of CustomModifier).GetInstance(customModifiers.Length)
builder.AddRange(customModifiers, i)
builder.Add(If(customModifiers(i).IsOptional, VisualBasicCustomModifier.CreateOptional(substituted), VisualBasicCustomModifier.CreateRequired(substituted)))
For j As Integer = i + 1 To customModifiers.Length - 1
modifier = DirectCast(customModifiers(j).Modifier, NamedTypeSymbol)
substituted = DirectCast(modifier.InternalSubstituteTypeParameters(Me).AsTypeSymbolOnly(), NamedTypeSymbol)
If modifier <> substituted Then
builder.Add(If(customModifiers(j).IsOptional, VisualBasicCustomModifier.CreateOptional(substituted), VisualBasicCustomModifier.CreateRequired(substituted)))
Else
builder.Add(customModifiers(j))
End If
Next
Debug.Assert(builder.Count = customModifiers.Length)
Return builder.ToImmutableAndFree()
End If
Next
Return customModifiers Return customModifiers
End Function End Function
......
...@@ -66,11 +66,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ...@@ -66,11 +66,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Function End Function
Function InternalSubstituteTypeParameters(substitution As TypeSubstitution) As TypeWithModifiers Function InternalSubstituteTypeParameters(substitution As TypeSubstitution) As TypeWithModifiers
Dim newCustomModifiers = If(substitution IsNot Nothing, substitution.SubstituteCustomModifiers(Me.CustomModifiers), Me.CustomModifiers)
Dim newTypeWithModifiers As TypeWithModifiers = Me.Type.InternalSubstituteTypeParameters(substitution) Dim newTypeWithModifiers As TypeWithModifiers = Me.Type.InternalSubstituteTypeParameters(substitution)
If Not newTypeWithModifiers.Is(Me.Type) Then If Not newTypeWithModifiers.Is(Me.Type) OrElse newCustomModifiers <> Me.CustomModifiers Then
Return New TypeWithModifiers(newTypeWithModifiers.Type, Me.CustomModifiers.Concat(newTypeWithModifiers.CustomModifiers)) Return New TypeWithModifiers(newTypeWithModifiers.Type, newCustomModifiers.Concat(newTypeWithModifiers.CustomModifiers))
Else Else
Return Me ' substitution had no effect on the type Return Me ' substitution had no effect on the type or modifiers
End If End If
End Function End Function
End Structure End Structure
......
...@@ -1318,5 +1318,220 @@ End Class ...@@ -1318,5 +1318,220 @@ End Class
Overriden") Overriden")
End Sub End Sub
<Fact, WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")>
Public Sub ModifiersWithConstructedType_01()
Dim ilSource = <![CDATA[
.class public auto ansi beforefieldinit CL1`1<valuetype .ctor ([mscorlib]System.ValueType) T1>
extends[mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006:
ret
} // end of method CL1`1::.ctor
.method public hidebysig newslot virtual
instance void Test(!T1 modopt(valuetype [mscorlib]System.Nullable`1<!T1>) t1) cil managed
{
// Code size 1 (0x1)
.maxstack 1
IL_0000: ldstr "Test"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method CL1`1::Test
} // end of class CL1`1
.class public auto ansi beforefieldinit CL2
extends class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>::.ctor()
IL_0006: ret
} // end of method CL2::.ctor
} // end of class CL2
]]>.Value
Dim vbSource =
<compilation>
<file name="c.vb"><![CDATA[
Class Module1
Shared Sub Main()
Dim x = new CL2()
x.Test(1)
x = new CL3()
x.Test(1)
End Sub
End Class
class CL3
Inherits CL2
public overrides Sub Test(c As Integer)
System.Console.WriteLine("Overriden")
end Sub
End Class
]]>
</file>
</compilation>
Dim compilation = CreateCompilationWithCustomILSource(vbSource, ilSource, options:=TestOptions.ReleaseExe)
CompileAndVerify(compilation, expectedOutput:="Test
Overriden")
End Sub
<Fact, WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")>
Public Sub ModifiersWithConstructedType_02()
Dim ilSource = <![CDATA[
.class public auto ansi beforefieldinit CL1`1<valuetype .ctor ([mscorlib]System.ValueType) T1>
extends[mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006:
ret
} // end of method CL1`1::.ctor
.method public hidebysig newslot virtual
instance void Test(!T1 modopt(valuetype [mscorlib]System.Nullable`1) t1) cil managed
{
// Code size 1 (0x1)
.maxstack 1
IL_0000: ldstr "Test"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method CL1`1::Test
} // end of class CL1`1
.class public auto ansi beforefieldinit CL2
extends class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>::.ctor()
IL_0006: ret
} // end of method CL2::.ctor
} // end of class CL2
]]>.Value
Dim vbSource =
<compilation>
<file name="c.vb"><![CDATA[
Class Module1
Shared Sub Main()
Dim x = new CL2()
x.Test(1)
x = new CL3()
x.Test(1)
End Sub
End Class
class CL3
Inherits CL2
public overrides Sub Test(c As Integer)
System.Console.WriteLine("Overriden")
end Sub
End Class
]]>
</file>
</compilation>
Dim compilation = CreateCompilationWithCustomILSource(vbSource, ilSource, options:=TestOptions.ReleaseExe)
CompileAndVerify(compilation, expectedOutput:="Test
Overriden")
End Sub
<Fact, WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")>
Public Sub ModifiersWithConstructedType_03()
Dim ilSource = <![CDATA[
.class public auto ansi beforefieldinit CL1`1<valuetype .ctor ([mscorlib]System.ValueType) T1>
extends[mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006:
ret
} // end of method CL1`1::.ctor
.method public hidebysig newslot virtual
instance int32 modopt(CL2) modopt(valuetype [mscorlib]System.Nullable`1<!T1>) modopt(valuetype [mscorlib]System.Nullable`1<!T1>) modopt(CL2) [] Test(!T1 t1) cil managed
{
// Code size 1 (0x1)
.maxstack 1
IL_0000: ldstr "Test"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_0006: ldnull
IL_000a: ret
} // end of method CL1`1::Test
} // end of class CL1`1
.class public auto ansi beforefieldinit CL2
extends class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void class CL1`1<int32 modopt([mscorlib]System.Runtime.CompilerServices.IsLong)>::.ctor()
IL_0006: ret
} // end of method CL2::.ctor
} // end of class CL2
]]>.Value
Dim vbSource =
<compilation>
<file name="c.vb"><![CDATA[
Class Module1
Shared Sub Main()
Dim x = new CL2()
x.Test(1)
x = new CL3()
x.Test(1)
End Sub
End Class
class CL3
Inherits CL2
public overrides Function Test(c As Integer) As Integer()
System.Console.WriteLine("Overriden")
return Nothing
end Function
End Class
]]>
</file>
</compilation>
Dim compilation = CreateCompilationWithCustomILSource(vbSource, ilSource, options:=TestOptions.ReleaseExe)
CompileAndVerify(compilation, expectedOutput:="Test
Overriden")
End Sub
End Class End Class
End Namespace End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册