diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 7340c903305fe08010c3f1439de6139984292ad8..8502e5671a69ff284a62d71abcfdb76527c0185f 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -2486,15 +2486,18 @@ private void EmitDefaultValue(TypeSymbol type, bool used, CSharpSyntaxNode synta { if (used) { - var constantValue = type.GetDefaultValue(); - if (constantValue != null) + // default type parameter values must be emitted as 'initobj' regardless of constraints + if (!type.IsTypeParameter()) { - _builder.EmitConstantValue(constantValue); - } - else - { - EmitInitObj(type, true, syntaxNode); + var constantValue = type.GetDefaultValue(); + if (constantValue != null) + { + _builder.EmitConstantValue(constantValue); + return; + } } + + EmitInitObj(type, true, syntaxNode); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs index fc2297f89618818b964831e2b32200281a282928..75bb1525369113fd551954a1542b870c6b50d730 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs @@ -31,7 +31,7 @@ private enum ConditionalAccessLoweringKind // IL gen can generate more compact code for certain conditional accesses // by utilizing stack dup/pop instructions - internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, bool used, BoundExpression rewrittenWhenNull = null) + internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, bool used) { Debug.Assert(!_inExpressionLambda); @@ -41,7 +41,7 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b // Check trivial case if (loweredReceiver.IsDefaultValue()) { - return rewrittenWhenNull ?? _factory.Default(node.Type); + return _factory.Default(node.Type); } ConditionalAccessLoweringKind loweringKind; @@ -154,7 +154,7 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b GetNullableMethod(node.Syntax, loweredReceiver.Type, SpecialMember.System_Nullable_T_get_HasValue) : null, loweredAccessExpression, - rewrittenWhenNull, + null, currentConditionalAccessID, type); @@ -180,7 +180,7 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b result = RewriteConditionalOperator(node.Syntax, condition, consequence, - rewrittenWhenNull ?? _factory.Default(nodeType), + _factory.Default(nodeType), null, nodeType); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs index 0accce94f45a463b5a7c18a7cb5e0ea67feedd57..4eec32a4aeaeee3daa6519f86ce7acf803c07f47 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs @@ -6843,5 +6843,56 @@ .locals init (int? V_0) } "); } + + [WorkItem(7388, "https://github.com/dotnet/roslyn/issues/7388")] + [Fact] + public void ConditionalClassConstrained001() + { + var source = @" +using System; + +namespace ConsoleApplication9 +{ + class Program + { + static void Main(string[] args) + { + var v = new A(); + System.Console.WriteLine(A.Test(v)); + } + + public class A : object where T : class + { + public T Value { get { return (T)(object)42; }} + + public static T Test(A val) + { + return val?.Value; + } + } + } +} + + +"; + var verifier = CompileAndVerify(source, expectedOutput: @"42"); + + verifier.VerifyIL("ConsoleApplication9.Program.A.Test(ConsoleApplication9.Program.A)", @" +{ + // Code size 20 (0x14) + .maxstack 1 + .locals init (T V_0) + IL_0000: ldarg.0 + IL_0001: brtrue.s IL_000d + IL_0003: ldloca.s V_0 + IL_0005: initobj ""T"" + IL_000b: ldloc.0 + IL_000c: ret + IL_000d: ldarg.0 + IL_000e: call ""T ConsoleApplication9.Program.A.Value.get"" + IL_0013: ret +}"); + } + } } diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitConversion.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitConversion.vb index 36f2e726ec2b5438a965a687d16264e64791898d..5f368b7e64d6e5d2c93520ad9faefe31c753007e 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitConversion.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitConversion.vb @@ -141,7 +141,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen Dim typeTo = conversion.Type If conversion.Operand.IsNothingLiteral Then - Debug.Assert(typeTo.IsValueType AndAlso Not typeTo.IsTypeParameter) + Debug.Assert(typeTo.IsValueType OrElse typeTo.IsTypeParameter) If used Then 'TODO: used diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb index 47d6be8bb8089666e076487b04cbb3bfe2a4a6a2..570a0b6275db167e53926de2948f5288c5f75fd5 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb @@ -2436,6 +2436,62 @@ C1 End Sub + + Public Sub ConstrainedToClass() + + Dim compilationDef = + + + + + Dim compilation = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(compilationDef, TestOptions.ReleaseExe) + + Dim verifier = CompileAndVerify(compilation, expectedOutput:= + ) + + verifier.VerifyIL("A(Of T).test(A(Of T))", + ) + + End Sub + Public Sub CodeGen_01()