static ConversionSymbol() { var conversions = (ConversionKind[])Enum.GetValues(typeof(ConversionKind)); simpleConv = new ConversionSymbol[conversions.Length]; foreach (var c in conversions) { simpleConv[(int)c] = new ConversionSymbol(c); } convCost = new int[conversions.Length]; #if DEBUG foreach (var c in conversions) { convCost[(int)c] = -1; } #endif convCost[(int)ConversionKind.NoConversion] = 0; convCost[(int)ConversionKind.NoImplicitConversion] = 0; convCost[(int)ConversionKind.Identity] = Implicit | 0; convCost[(int)ConversionKind.ImplicitEnumeration] = Implicit | 1; convCost[(int)ConversionKind.ImplicitNumeric] = Implicit | 1; convCost[(int)ConversionKind.ImplicitNullable] = Implicit | 2; //convCost[(int)ConversionKind.NullLiteral] = Implicit | 0; convCost[(int)ConversionKind.ImplicitReference] = Implicit | 0; convCost[(int)ConversionKind.Boxing] = Implicit | 3; convCost[(int)ConversionKind.ImplicitUsual] = Implicit | 4; convCost[(int)ConversionKind.ImplicitUserDefined] = Implicit | 4; convCost[(int)ConversionKind.Refer] = Implicit | 0; convCost[(int)ConversionKind.Deref] = Implicit | 0; convCost[(int)ConversionKind.ConstantReduction] = Implicit | 0; convCost[(int)ConversionKind.ExplicitEnumeration] = Explicit | 1; convCost[(int)ConversionKind.ExplicitNumeric] = Explicit | 1; convCost[(int)ConversionKind.ExplicitNullable] = Explicit | 2; convCost[(int)ConversionKind.ExplicitReference] = Explicit | 0; convCost[(int)ConversionKind.Unboxing] = Explicit | Cast | 3; convCost[(int)ConversionKind.ExplicitUsual] = Explicit | 4; convCost[(int)ConversionKind.ExplicitUserDefined] = Explicit | 4; #if DEBUG foreach (var cost in convCost) { Debug.Assert(cost >= 0); } #endif }
internal static ConversionSymbol ResolveUsualConversion(Expr expr, TypeSymbol type, BindOptions options) { if (expr.Datatype.NativeType == NativeType.Usual) { if (type.NativeType == NativeType.Object) { if (options.HasFlag(BindOptions.BoxUsual)) { return(ConversionSymbol.Create(ConversionKind.Boxing)); } else { MethodSymbol converter = null; ResolveConversionMethod(expr, type, Compilation.Get(NativeType.Usual).Lookup(XSharpFunctionNames.ToObject), ref converter, options); if (converter != null) { return(ConversionSymbol.Create(ConversionKind.ImplicitUserDefined, converter)); } } } else { MethodSymbol converter = null; ResolveConversionMethod(expr, Compilation.Get(NativeType.Object), Compilation.Get(NativeType.Usual).Lookup(XSharpFunctionNames.ToObject), ref converter, options); if (converter != null) { var inner = ConversionSymbol.Create(ConversionKind.ImplicitUserDefined, converter); var outer = type.IsReferenceType ? ConversionSymbol.Create(ConversionKind.ExplicitReference) : type.IsValueType ? ConversionSymbol.Create(ConversionKind.Unboxing) : ConversionSymbol.Create(ConversionKind.NoConversion); if (outer.Exists) { return(ConversionSymbol.Create(outer, inner)); } } } } else if (type.NativeType == NativeType.Usual && expr.Datatype.IsReferenceType) { var inner = Conversion(expr, Compilation.Get(NativeType.Object), options | BindOptions.Explicit); if (inner.Exists) { var outer = Conversion(TypeConversion.Bound(expr, Compilation.Get(NativeType.Object), inner), type, options); if (outer.Exists) { return(ConversionSymbol.Create(outer, inner)); } } } return(null); }
Arg ApplyUsualConversions(ArgList args, out Expr writeBack) { writeBack = null; bool hasRefArgs = false; for (int i = 0; i < args.Args.Count; i++) { var e = args.Args[i].Expr; Convert(ref e, Compilation.Get(NativeType.Usual)); if (args.Args[i].RefKind != RefKind.None) { hasRefArgs = true; } } var arguments = new Arg(LiteralArray.Bound(args.Args)); if (hasRefArgs) { var conv = ConversionSymbol.Create(ConversionSymbol.Create(ConversionKind.Identity), new ConversionToTemp(arguments.Expr.Datatype)); Convert(ref arguments.Expr, arguments.Expr.Datatype, conv); for (int i = 0; i < args.Args.Count; i++) { if (args.Args[i].RefKind != RefKind.None) { HandleVarArgWriteBack(conv, args.Args[i].Expr, i, ref writeBack); } } } return(arguments); void HandleVarArgWriteBack(ConversionSymbol conv, Expr e, int i, ref Expr wb) { if (e.Symbol?.HasSetAccess == true || e is AutoVarExpr || e is AliasExpr) { // Handle writeBack Expr t = IdExpr.Bound(conv.IndirectRefConversionTempLocal()); t = ArrayAccessExpr.Bound(t, ArgList.Bound(LiteralExpr.Bound(Constant.Create(i + 1))), this); var wc = Conversion(t, e.Datatype, BindOptions.Default); if (wc.Exists) { Convert(ref t, e.Datatype, wc); SymbolExtensions.AddExpr(ref wb, AssignExpr.Bound(e, t, BindOptions.Default)); } } } }
internal static bool CheckBinaryOperator(Expr left, Expr right, MethodSymbol m, ref ConversionSymbol lconv, ref ConversionSymbol rconv, BindOptions options) { var method = m.Method; if (!m.Method.IsStatic || (options.HasFlag(BindOptions.Special) && !m.Method.IsSpecialName)) { return(false); } var parameters = method.GetParameters(); if (parameters.Length != 2) { return(false); } var ltype = FindType(parameters[0].ParameterType); var rtype = FindType(parameters[1].ParameterType); if (TypesMatch(ltype, left.Datatype) && TypesMatch(rtype, right.Datatype)) { lconv = ConversionSymbol.Create(ConversionKind.Identity); rconv = ConversionSymbol.Create(ConversionKind.Identity); return(true); } var _lconv = Conversion(left, ltype, options); var _rconv = Conversion(right, rtype, options); if (_lconv.IsImplicit && _rconv.IsImplicit) { if (lconv == null && rconv == null) { lconv = _lconv; rconv = _rconv; return(true); } var cost = lconv?.Cost + rconv?.Cost; var _cost = _lconv.Cost + _rconv.Cost; if (_cost < cost) { lconv = _lconv; rconv = _rconv; return(true); } } return(false); }
internal static ConversionSymbol ResolveByRefConversion(Expr expr, TypeSymbol type, BindOptions options) { if (type.IsByRef && TypesMatch(expr.Datatype, type.ElementType)) { return(ConversionSymbol.CreateByRef()); } else { var inner = ConversionSymbol.Create(ConversionKind.Deref); var outer = Conversion(TypeConversion.Bound(expr, expr.Datatype.ElementType, inner), type, options); if (outer.Exists) { return(ConversionSymbol.Create(outer, inner)); } } return(null); }
internal ConversionToTemp(ConversionSymbol conv, TypeSymbol type) : base(conv.Kind) { Conversion = conv; Type = type; }
internal ConversionChain(ConversionSymbol conv, ConversionSymbol prev) : base(conv.Kind) { Conversion = conv; Previous = prev; }
void ApplyConversions(ArgList args, OverloadResult ovRes, out Expr writeBack) { writeBack = null; var parameters = ovRes.Parameters.Parameters; for (int i = 0; i < ovRes.FixedArgs; i++) { var conv = ovRes.Conversions[i]; var e = args.Args[i].Expr; if (conv.Kind != ConversionKind.Identity) { Convert(ref args.Args[i].Expr, FindType(parameters[i].ParameterType), conv); } if (conv is ConversionSymbolToConstant) { Convert(ref args.Args[i].Expr, FindType(parameters[i].ParameterType), BindOptions.Default); } HandleArgWriteBack(conv, e, ref writeBack); } if (ovRes.MissingArgs > 0) { for (int i = ovRes.FixedArgs; i < ovRes.FixedArgs + ovRes.MissingArgs; i++) { var conv = ovRes.Conversions[i]; var a = new Arg(LiteralExpr.Bound(((ConversionSymbolToConstant)conv).Constant)); Convert(ref a.Expr, FindType(parameters[i].ParameterType), BindOptions.Default); args.Args.Add(a); } } else if (ovRes.Parameters.HasParamArray) { var varArgs = new List <Expr>(ovRes.VarArgs); var varArgType = FindType(parameters[ovRes.FixedArgs].ParameterType.GetElementType()); bool hasRefArgs = false; for (int i = ovRes.FixedArgs; i < ovRes.FixedArgs + ovRes.VarArgs; i++) { var conv = ovRes.Conversions[i]; var e = args.Args[i].Expr; Convert(ref e, varArgType, conv); varArgs.Add(e); if (args.Args[i].RefKind != RefKind.None) { hasRefArgs = true; } } var varArg = new Arg(LiteralArray.Bound(varArgs, varArgType)); if (hasRefArgs) { var conv = ConversionSymbol.Create(ConversionSymbol.Create(ConversionKind.Identity), new ConversionToTemp(varArg.Expr.Datatype)); Convert(ref varArg.Expr, varArg.Expr.Datatype, conv); for (int i = ovRes.FixedArgs; i < ovRes.FixedArgs + ovRes.VarArgs; i++) { if (args.Args[i].RefKind != RefKind.None) { HandleVarArgWriteBack(conv, args.Args[i].Expr, i - ovRes.FixedArgs, ref writeBack); } } } while (args.Args.Count > ovRes.FixedArgs) { args.Args.RemoveAt(args.Args.Count - 1); } args.Args.Add(varArg); } void HandleArgWriteBack(ConversionSymbol conv, Expr e, ref Expr wb) { if (conv.IsIndirectRefConversion()) { if (e.Symbol?.HasSetAccess == true || e is AutoVarExpr || e is AliasExpr) { // Handle writeBack Expr t = IdExpr.Bound(conv.IndirectRefConversionTempLocal()); var wc = Conversion(t, e.Datatype, BindOptions.Default); if (wc.Exists) { Convert(ref t, e.Datatype, wc); SymbolExtensions.AddExpr(ref wb, AssignExpr.Bound(e, t, BindOptions.Default)); } } } } void HandleVarArgWriteBack(ConversionSymbol conv, Expr e, int i, ref Expr wb) { if (e.Symbol?.HasSetAccess == true || e is AutoVarExpr || e is AliasExpr) { // Handle writeBack Expr t = IdExpr.Bound(conv.IndirectRefConversionTempLocal()); t = ArrayAccessExpr.Bound(t, ArgList.Bound(LiteralExpr.Bound(Constant.Create(i + 1))), this); var wc = Conversion(t, e.Datatype, BindOptions.Default); if (wc.Exists) { Convert(ref t, e.Datatype, wc); SymbolExtensions.AddExpr(ref wb, AssignExpr.Bound(e, t, BindOptions.Default)); } } } }
internal static BinaryOperatorSymbol UserDefinedBinaryOperator(BinaryOperatorKind kind, ref Expr left, ref Expr right, BindOptions options) { MethodSymbol mop = null; ConversionSymbol lconv = null; ConversionSymbol rconv = null; bool hasUsual = left.Datatype.NativeType == NativeType.Usual || right.Datatype.NativeType == NativeType.Usual; if (options.HasFlag(BindOptions.AllowInexactComparisons)) { bool hasString = left.Datatype.NativeType == NativeType.String || right.Datatype.NativeType == NativeType.String; bool bothStrings = left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String; switch (kind) { case BinaryOperatorKind.Equal: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringEquals), ref mop, ref lconv, ref rconv, options); } else if (hasString) { ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactEquals), ref mop, ref lconv, ref rconv, options); } break; case BinaryOperatorKind.NotEqual: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringNotEquals), ref mop, ref lconv, ref rconv, options); } else if (hasString) { ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactNotEquals), ref mop, ref lconv, ref rconv, options); } break; case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThanOrEqual: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringCompare), ref mop, ref lconv, ref rconv, options); } break; } } else { switch (kind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThanOrEqual: if (left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.System_String_CompareOrdinal), ref mop, ref lconv, ref rconv, options); } break; } } if (mop == null) { var name = BinaryOperatorSymbol.OperatorName(kind); if (name != null) { ResolveBinaryOperator(left, right, left.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special); ResolveBinaryOperator(left, right, right.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special); } } if (mop == null && kind == BinaryOperatorKind.Exponent) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions_POW), ref mop, ref lconv, ref rconv, options); if (hasUsual) { ResolveBinaryOperator(left, right, left.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options); ResolveBinaryOperator(left, right, right.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options); } } if (mop != null) { var op = BinaryOperatorSymbol.Create(kind, mop, lconv, rconv); ApplyBinaryOperator(ref left, ref right, op); return(op); } return(null); }
internal ConversionToTemp(TypeSymbol type) : base(ConversionKind.ImplicitUserDefined) { Conversion = ConversionSymbol.Create(ConversionKind.Identity); Type = type; Local = new LocalSymbol(Type); }
internal ConversionToTemp(ConversionSymbol conv, TypeSymbol type) : base(conv.Kind == ConversionKind.Identity ? ConversionKind.ImplicitUserDefined : conv.Kind) { Conversion = conv; Type = type; Local = new LocalSymbol(Type); }
internal ConversionChain(ConversionSymbol conv, ConversionSymbol prev) : base(conv.Kind == ConversionKind.Identity ? ConversionKind.ImplicitUserDefined : conv.Kind) { Conversion = conv; Previous = prev; }
internal static UnaryOperatorSymbolWithMethod Create(UnaryOperatorKind kind, MethodSymbol method, ConversionSymbol conv) { return(new UnaryOperatorSymbolWithMethod(kind, method, conv)); }
internal UnaryOperatorSymbolWithMethod(UnaryOperatorKind kind, MethodSymbol method, ConversionSymbol conv) : base(kind, OperandType.Error) { Method = method; Conv = conv; }