public override BoundNode VisitConvertedTupleLiteral(BoundConvertedTupleLiteral node) { if (_inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsTupleLiteral, node); } return(base.VisitConvertedTupleLiteral(node)); }
public override BoundNode VisitConvertedTupleLiteral(BoundConvertedTupleLiteral node) { return(VisitTupleExpression(node)); }
protected BoundExpression CreateConversion( CSharpSyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, bool wasCompilerGenerated, TypeSymbol destination, DiagnosticBag diagnostics) { Debug.Assert(source != null); Debug.Assert((object)destination != null); if (conversion.IsIdentity) { // identity tuple conversions result in a converted tuple // to indicate that tuple conversions are no longer applicable. // nothing else changes if (source.Kind == BoundKind.TupleLiteral) { var sourceTuple = (BoundTupleLiteral)source; source = new BoundConvertedTupleLiteral( sourceTuple.Syntax, sourceTuple.Type, sourceTuple.Arguments, sourceTuple.Type, // same type to keep original element names sourceTuple.HasErrors); } // We need to preserve any conversion that changes the type (even identity conversions, like object->dynamic), // or that was explicitly written in code (so that GetSemanticInfo can find the syntax in the bound tree). if (!isCast && source.Type == destination) { return source; } } ReportDiagnosticsIfObsolete(diagnostics, conversion, syntax, hasBaseReceiver: false); if (conversion.IsMethodGroup) { return CreateMethodGroupConversion(syntax, source, conversion, isCast, destination, diagnostics); } if (conversion.IsAnonymousFunction && source.Kind == BoundKind.UnboundLambda) { return CreateAnonymousFunctionConversion(syntax, source, conversion, isCast, destination, diagnostics); } if (conversion.IsTupleLiteral || (conversion.Kind == ConversionKind.ImplicitNullable && source.Kind == BoundKind.TupleLiteral)) { return CreateTupleLiteralConversion(syntax, (BoundTupleLiteral)source, conversion, isCast, destination, diagnostics); } if (conversion.IsUserDefined) { return CreateUserDefinedConversion(syntax, source, conversion, isCast, destination, diagnostics); } ConstantValue constantValue = this.FoldConstantConversion(syntax, source, conversion, destination, diagnostics); return new BoundConversion( syntax, source, conversion, IsCheckedConversion(source.Type, destination), explicitCastInCode: isCast && !wasCompilerGenerated, constantValueOpt: constantValue, type: destination) { WasCompilerGenerated = wasCompilerGenerated }; }
private BoundExpression CreateTupleLiteralConversion(CSharpSyntaxNode syntax, BoundTupleLiteral sourceTuple, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics) { // We have a successful tuple conversion; rather than producing a separate conversion node // which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments. Debug.Assert(conversion.Kind == ConversionKind.ImplicitTupleLiteral || conversion.Kind == ConversionKind.ImplicitNullable); Debug.Assert((conversion.Kind == ConversionKind.ImplicitNullable) == destination.IsNullableType()); TypeSymbol destinationWithoutNullable = conversion.Kind == ConversionKind.ImplicitNullable ? destinationWithoutNullable = destination.GetNullableUnderlyingType() : destination; NamedTypeSymbol targetType = (NamedTypeSymbol)destinationWithoutNullable; if (targetType.IsTupleType) { var destTupleType = (TupleTypeSymbol)targetType; // do not lose the original element names in the literal if different from names in the target // Come back to this, what about locations? (https://github.com/dotnet/roslyn/issues/11013) targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt); } var arguments = sourceTuple.Arguments; var convertedArguments = ArrayBuilder<BoundExpression>.GetInstance(arguments.Length); ImmutableArray<TypeSymbol> targetElementTypes = targetType.GetElementTypesOfTupleOrCompatible(); Debug.Assert(targetElementTypes.Length == arguments.Length, "converting a tuple literal to incompatible type?"); for (int i = 0; i < arguments.Length; i++) { var argument = arguments[i]; var destType = targetElementTypes[i]; HashSet<DiagnosticInfo> useSiteDiagnostics = null; Conversion elementConversion; if (isCast) { elementConversion = this.Conversions.ClassifyConversionForCast(argument, destType, ref useSiteDiagnostics); } else { elementConversion = this.Conversions.ClassifyConversionFromExpression(argument, destType, ref useSiteDiagnostics); } diagnostics.Add(syntax, useSiteDiagnostics); convertedArguments.Add(CreateConversion(argument.Syntax, argument, elementConversion, isCast, destType, diagnostics)); } BoundExpression result = new BoundConvertedTupleLiteral( sourceTuple.Syntax, sourceTuple.Type, convertedArguments.ToImmutableAndFree(), targetType); // We need to preserve any conversion that changes the type (even identity conversions), // or that was explicitly written in code (so that GetSemanticInfo can find the syntax in the bound tree). if (!isCast && targetType == destination) { return result; } // if we have a nullable cast combined with a name/dynamic cast // name/dynamic cast must happen before converting to nullable if (conversion.Kind == ConversionKind.ImplicitNullable && destinationWithoutNullable != targetType) { Debug.Assert(destinationWithoutNullable.Equals(targetType, ignoreDynamic: true)); result = new BoundConversion( syntax, result, Conversion.Identity, @checked: false, explicitCastInCode: isCast, constantValueOpt: ConstantValue.NotAvailable, type: destinationWithoutNullable) { WasCompilerGenerated = sourceTuple.WasCompilerGenerated }; } return new BoundConversion( syntax, result, conversion, @checked: false, explicitCastInCode: isCast, constantValueOpt: ConstantValue.NotAvailable, type: destination) { WasCompilerGenerated = sourceTuple.WasCompilerGenerated }; }
private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTupleLiteral sourceTuple, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics) { // We have a successful tuple conversion; rather than producing a separate conversion node // which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments. Debug.Assert((conversion.Kind == ConversionKind.ImplicitNullable) == destination.IsNullableType()); var destinationWithoutNullable = destination; var conversionWithoutNullable = conversion; if (conversion.Kind == ConversionKind.ImplicitNullable) { destinationWithoutNullable = destination.GetNullableUnderlyingType(); conversionWithoutNullable = conversion.UnderlyingConversions[0]; } Debug.Assert(conversionWithoutNullable.IsTupleLiteralConversion); NamedTypeSymbol targetType = (NamedTypeSymbol)destinationWithoutNullable; if (targetType.IsTupleType) { var destTupleType = (TupleTypeSymbol)targetType; // do not lose the original element names in the literal if different from names in the target TupleTypeSymbol.ReportNamesMismatchesIfAny(targetType, sourceTuple, diagnostics); // Come back to this, what about locations? (https://github.com/dotnet/roslyn/issues/11013) targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt); } var arguments = sourceTuple.Arguments; var convertedArguments = ArrayBuilder<BoundExpression>.GetInstance(arguments.Length); ImmutableArray<TypeSymbol> targetElementTypes = targetType.GetElementTypesOfTupleOrCompatible(); Debug.Assert(targetElementTypes.Length == arguments.Length, "converting a tuple literal to incompatible type?"); var underlyingConversions = conversionWithoutNullable.UnderlyingConversions; for (int i = 0; i < arguments.Length; i++) { var argument = arguments[i]; var destType = targetElementTypes[i]; var elementConversion = underlyingConversions[i]; convertedArguments.Add(CreateConversion(argument.Syntax, argument, elementConversion, isCast, destType, diagnostics)); } BoundExpression result = new BoundConvertedTupleLiteral( sourceTuple.Syntax, sourceTuple.Type, convertedArguments.ToImmutableAndFree(), targetType); if (sourceTuple.Type != destination) { // literal cast is applied to the literal result = new BoundConversion( sourceTuple.Syntax, result, conversion, @checked: false, explicitCastInCode: isCast, constantValueOpt: ConstantValue.NotAvailable, type: destination); } // If we had a cast in the code, keep conversion in the tree. // even though the literal is already converted to the target type. if (isCast) { result = new BoundConversion( syntax, result, Conversion.Identity, @checked: false, explicitCastInCode: isCast, constantValueOpt: ConstantValue.NotAvailable, type: destination); } return result; }
public override BoundNode VisitConvertedTupleLiteral(BoundConvertedTupleLiteral node) { return VisitTupleExpression(node); }
public override BoundNode VisitConvertedTupleLiteral(BoundConvertedTupleLiteral node) { if (_inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsTupleLiteral, node); } return base.VisitConvertedTupleLiteral(node); }