Skip to content

Commit

Permalink
Fixes: dotnet#11689
Browse files Browse the repository at this point in the history
  • Loading branch information
VSadov committed Sep 28, 2016
1 parent 47c3248 commit 7b5e3d3
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 21 deletions.
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4929,6 +4929,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="WRN_TupleLiteralNameMismatch_Title" xml:space="preserve">
<value>The tuple element name is ignored because a different name is specified by the assignment target.</value>
</data>
<data name="ERR_PredefinedValueTupleTypeMustBeStruct" xml:space="preserve">
<value>Predefined type '{0}' must be a struct.</value>
</data>
<data name="ERR_DeconstructionVarFormDisallowsSpecificType" xml:space="preserve">
<value>Deconstruction 'var (...)' form disallows a specific type for 'var'.</value>
</data>
Expand Down
15 changes: 14 additions & 1 deletion src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal abstract class PEModuleBuilder : PEModuleBuilder<CSharpCompilation, Sou
// TODO: Need to estimate amount of elements for this map and pass that value to the constructor.
protected readonly ConcurrentDictionary<Symbol, Cci.IModuleReference> AssemblyOrModuleSymbolToModuleRefMap = new ConcurrentDictionary<Symbol, Cci.IModuleReference>();
private readonly ConcurrentDictionary<Symbol, object> _genericInstanceMap = new ConcurrentDictionary<Symbol, object>();
private readonly ConcurrentSet<ErrorTypeSymbol> _reportedErrorTypesMap = new ConcurrentSet<ErrorTypeSymbol>();
private readonly ConcurrentSet<TypeSymbol> _reportedErrorTypesMap = new ConcurrentSet<TypeSymbol>();

private readonly NoPia.EmbeddedTypesManager _embeddedTypesManagerOpt;
public override NoPia.EmbeddedTypesManager EmbeddedTypesManagerOpt
Expand Down Expand Up @@ -790,6 +790,19 @@ internal Cci.INamedTypeReference Translate(
{
Debug.Assert(!needDeclaration);
namedTypeSymbol = namedTypeSymbol.TupleUnderlyingType;

// check that underlying type of a ValueTuple is indeed a value type (or error)
// this should never happen, in theory,
// but if it does happen we should make it a failure.
var declaredBase = namedTypeSymbol.BaseTypeNoUseSiteDiagnostics;
if (declaredBase.SpecialType != SpecialType.System_ValueType && !declaredBase.IsErrorType())
{
// Try to decrease noise by not complaining about the same type over and over again.
if (_reportedErrorTypesMap.Add(namedTypeSymbol))
{
diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, namedTypeSymbol.MetadataName), syntaxNodeOpt == null ? NoLocation.Singleton : syntaxNodeOpt.Location));
}
}
}

// Substitute error types with a special singleton object.
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,9 @@ internal enum ErrorCode

ERR_PredefinedValueTupleTypeNotFound = 8179,
ERR_SemiOrLBraceOrArrowExpected = 8180,
ERR_PredefinedValueTupleTypeMustBeStruct = 8180,

// Available = 8180-8195

// Available = 8181-8195

Expand Down
23 changes: 3 additions & 20 deletions src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -663,22 +663,6 @@ internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics
return _underlyingType.InterfacesNoUseSiteDiagnostics(basesBeingResolved);
}

public override bool IsReferenceType
{
get
{
return _underlyingType.IsErrorType() ? false : _underlyingType.IsReferenceType;
}
}

public override bool IsValueType
{
get
{
return _underlyingType.IsErrorType() || _underlyingType.IsValueType;
}
}

internal sealed override bool IsManagedType
{
get
Expand Down Expand Up @@ -1097,10 +1081,9 @@ public override TypeKind TypeKind
{
get
{
// only classes and structs can have instance fields as tuple requires.
// we need to have some support for classes, but most common case will be struct
// in broken scenarios (ErrorType, Enum, Delegate, whatever..) we will just default to struct.
return _underlyingType.TypeKind == TypeKind.Class ? TypeKind.Class : TypeKind.Struct;
// From the language prospective tuple is a value type
// composed of its underlying elements
return TypeKind.Struct;
}
}

Expand Down
223 changes: 223 additions & 0 deletions src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18790,5 +18790,228 @@ static void Main()
});
// no assert hit
}

[Fact]
[WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")]
public void ValueTupleNotStruct0()
{
var source = @"
class C
{
static void Main()
{
(int a, int b) x;
x.Item1 = 1;
x.b = 2;

// by the language rules tuple x is definitely assigned
// since all its elements are definitely assigned
System.Console.WriteLine(x);
}
}

namespace System
{
public class ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;

public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}

" + tupleattributes_cs;

var comp = CreateCompilationWithMscorlib(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe);

comp.VerifyEmitDiagnostics(
// (6,24): error CS8182: Predefined type 'ValueTuple`2' must be a struct.
// (int a, int b) x;
Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "x").WithArguments("ValueTuple`2").WithLocation(6, 24)
);

}


[Fact]
[WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")]
public void ValueTupleNotStruct1()
{
var source = @"
class C
{
static void Main()
{
var x = (1, 1);

System.Console.WriteLine(x);
}
}

namespace System
{
public class ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;

public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}

" + tupleattributes_cs;

var comp = CreateCompilationWithMscorlib(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe);

comp.VerifyEmitDiagnostics(
// (6,13): error CS8180: Predefined type 'ValueTuple`2' must be a struct.
// var x = (1, 1);
Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "x = (1, 1)").WithArguments("ValueTuple`2").WithLocation(6, 13)
);

}

[Fact]
[WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")]
public void ValueTupleNotStruct2()
{
var source = @"
class C
{
static void Main()
{
}

static void Test2((int a, int b) arg)
{
}
}

namespace System
{
public class ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;

public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}

" + tupleattributes_cs;

var comp = CreateCompilationWithMscorlib(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe);

comp.VerifyEmitDiagnostics(
// error CS8180: Predefined type 'ValueTuple`2' must be a struct.
Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct).WithArguments("ValueTuple`2").WithLocation(1, 1)
);

}

[Fact]
[WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")]
public void ValueTupleNotStruct3()
{
var source = @"
class C
{
static void Main()
{
}

static void Test1()
{
(int, int)[] x = null;

System.Console.WriteLine(x);
}
}

namespace System
{
public class ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;

public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}

" + tupleattributes_cs;

var comp = CreateCompilationWithMscorlib(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe);

comp.VerifyEmitDiagnostics(
// (10,22): error CS8180: Predefined type 'ValueTuple`2' must be a struct.
// (int, int)[] x = null;
Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "x = null").WithArguments("ValueTuple`2").WithLocation(10, 22)
);

}

[Fact]
[WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")]
public void ValueTupleNotStruct4()
{
var source = @"
class C
{
static void Main()
{
}

static (int a, int b) Test2()
{
return (1, 1);
}
}

namespace System
{
public class ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;

public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}

" + tupleattributes_cs;

var comp = CreateCompilationWithMscorlib(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe);

comp.VerifyEmitDiagnostics(
// (9,5): error CS8180: Predefined type 'ValueTuple`2' must be a struct.
// {
Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, @"{
return (1, 1);
}").WithArguments("ValueTuple`2").WithLocation(9, 5)
);

}
}
}

0 comments on commit 7b5e3d3

Please sign in to comment.