📄 convert.cs
字号:
break; } } EmptyExpression.Release (expr); return best; } /// <summary> /// Finds "most encompassing type" according to the spec (13.4.2) /// amongst the types in the given set /// </summary> static Type FindMostEncompassingType (EmitContext ec, ArrayList types) { Type best = null; if (types.Count == 0) return null; if (types.Count == 1) return (Type) types [0]; EmptyExpression expr = EmptyExpression.Grab (); foreach (Type t in types) { if (best == null) { best = t; continue; } expr.SetType (best); if (ImplicitStandardConversionExists (ec, expr, t)) best = t; } foreach (Type t in types) { if (best == t) continue; expr.SetType (t); if (!ImplicitStandardConversionExists (ec, expr, best)) { best = null; break; } } EmptyExpression.Release (expr); return best; } /// <summary> /// Finds the most specific source Sx according to the rules of the spec (13.4.4) /// by making use of FindMostEncomp* methods. Applies the correct rules separately /// for explicit and implicit conversion operators. /// </summary> static public Type FindMostSpecificSource (EmitContext ec, IList list, Expression source, bool apply_explicit_conv_rules) { ArrayList src_types_set = new ArrayList (); // // If any operator converts from S then Sx = S // Type source_type = source.Type; foreach (MethodBase mb in list){ ParameterData pd = TypeManager.GetParameterData (mb); Type param_type = pd.ParameterType (0); if (param_type == source_type) return param_type; src_types_set.Add (param_type); } // // Explicit Conv rules // if (apply_explicit_conv_rules) { ArrayList candidate_set = new ArrayList (); foreach (Type param_type in src_types_set){ if (ImplicitStandardConversionExists (ec, source, param_type)) candidate_set.Add (param_type); } if (candidate_set.Count != 0) return FindMostEncompassedType (ec, candidate_set); } // // Final case // if (apply_explicit_conv_rules) return FindMostEncompassingType (ec, src_types_set); else return FindMostEncompassedType (ec, src_types_set); } /// <summary> /// Finds the most specific target Tx according to section 13.4.4 /// </summary> static public Type FindMostSpecificTarget (EmitContext ec, IList list, Type target, bool apply_explicit_conv_rules) { ArrayList tgt_types_set = new ArrayList (); // // If any operator converts to T then Tx = T // foreach (MethodInfo mi in list){ Type ret_type = mi.ReturnType; if (ret_type == target) return ret_type; tgt_types_set.Add (ret_type); } // // Explicit conv rules // if (apply_explicit_conv_rules) { ArrayList candidate_set = new ArrayList (); EmptyExpression expr = EmptyExpression.Grab (); foreach (Type ret_type in tgt_types_set){ expr.SetType (ret_type); if (ImplicitStandardConversionExists (ec, expr, target)) candidate_set.Add (ret_type); } EmptyExpression.Release (expr); if (candidate_set.Count != 0) return FindMostEncompassingType (ec, candidate_set); } // // Okay, final case ! // if (apply_explicit_conv_rules) return FindMostEncompassedType (ec, tgt_types_set); else return FindMostEncompassingType (ec, tgt_types_set); } /// <summary> /// User-defined Implicit conversions /// </summary> static public Expression ImplicitUserConversion (EmitContext ec, Expression source, Type target, Location loc) { return UserDefinedConversion (ec, source, target, loc, false); } /// <summary> /// User-defined Explicit conversions /// </summary> static public Expression ExplicitUserConversion (EmitContext ec, Expression source, Type target, Location loc) { return UserDefinedConversion (ec, source, target, loc, true); } static void AddConversionOperators (EmitContext ec, ArrayList list, Expression source, Type target_type, bool look_for_explicit, MethodGroupExpr mg) { if (mg == null) return; Type source_type = source.Type; EmptyExpression expr = EmptyExpression.Grab (); foreach (MethodInfo m in mg.Methods) { ParameterData pd = TypeManager.GetParameterData (m); Type return_type = m.ReturnType; Type arg_type = pd.ParameterType (0); if (source_type != arg_type) { if (!ImplicitStandardConversionExists (ec, source, arg_type)) { if (!look_for_explicit) continue; expr.SetType (arg_type); if (!ImplicitStandardConversionExists (ec, expr, source_type)) continue; } } if (target_type != return_type) { expr.SetType (return_type); if (!ImplicitStandardConversionExists (ec, expr, target_type)) { if (!look_for_explicit) continue; expr.SetType (target_type); if (!ImplicitStandardConversionExists (ec, expr, return_type)) continue; } } list.Add (m); } EmptyExpression.Release (expr); } /// <summary> /// Compute the user-defined conversion operator from source_type to target_type. /// `look_for_explicit' controls whether we should also include the list of explicit operators /// </summary> static MethodInfo GetConversionOperator (EmitContext ec, Expression source, Type target_type, bool look_for_explicit) { ArrayList ops = new ArrayList (4); Type source_type = source.Type; if (source_type != TypeManager.decimal_type) { AddConversionOperators (ec, ops, source, target_type, look_for_explicit, Expression.MethodLookup (ec, source_type, "op_Implicit", Location.Null) as MethodGroupExpr); if (look_for_explicit) { AddConversionOperators (ec, ops, source, target_type, look_for_explicit, Expression.MethodLookup ( ec, source_type, "op_Explicit", Location.Null) as MethodGroupExpr); } } if (target_type != TypeManager.decimal_type) { AddConversionOperators (ec, ops, source, target_type, look_for_explicit, Expression.MethodLookup (ec, target_type, "op_Implicit", Location.Null) as MethodGroupExpr); if (look_for_explicit) { AddConversionOperators (ec, ops, source, target_type, look_for_explicit, Expression.MethodLookup ( ec, target_type, "op_Explicit", Location.Null) as MethodGroupExpr); } } if (ops.Count == 0) return null; Type most_specific_source = FindMostSpecificSource (ec, ops, source, look_for_explicit); if (most_specific_source == null) return null; Type most_specific_target = FindMostSpecificTarget (ec, ops, target_type, look_for_explicit); if (most_specific_target == null) return null; MethodInfo method = null; foreach (MethodInfo m in ops) { if (m.ReturnType != most_specific_target) continue; if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source) continue; // Ambiguous: more than one conversion operator satisfies the signature. if (method != null) return null; method = m; } return method; } static DoubleHash explicit_conv = new DoubleHash (100); static DoubleHash implicit_conv = new DoubleHash (100); /// <summary> /// User-defined conversions /// </summary> static public Expression UserDefinedConversion (EmitContext ec, Expression source, Type target, Location loc, bool look_for_explicit) { Type source_type = source.Type; MethodInfo method = null; object o; DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv; if (!(source is Constant) && hash.Lookup (source_type, target, out o)) { method = (MethodInfo) o; } else { method = GetConversionOperator (ec, source, target, look_for_explicit); if (!(source is Constant)) hash.Insert (source_type, target, method); } if (method == null) return null; Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0); // // This will do the conversion to the best match that we // found. Now we need to perform an implict standard conversion // if the best match was not the type that we were requested // by target. // if (look_for_explicit) source = ExplicitConversionStandard (ec, source, most_specific_source, loc); else source = ImplicitConversionStandard (ec, source, most_specific_source, loc); if (source == null) return null; Expression e; e = new UserCast (method, source, loc); if (e.Type != target){ if (!look_for_explicit) e = ImplicitConversionStandard (ec, e, target, loc); else e = ExplicitConversionStandard (ec, e, target, loc); } return e; } /// <summary> /// Converts implicitly the resolved expression `expr' into the /// `target_type'. It returns a new expression that can be used /// in a context that expects a `target_type'. /// </summary> static public Expression ImplicitConversion (EmitContext ec, Expression expr, Type target_type, Location loc) { Expression e; if (target_type == null) throw new Exception ("Target type is null"); e = ImplicitConversionStandard (ec, expr, target_type, loc); if (e != null) return e; e = ImplicitUserConversion (ec, expr, target_type, loc); if (e != null) return e; return null; } /// <summary> /// Attempts to apply the `Standard Implicit /// Conversion' rules to the expression `expr' into /// the `target_type'. It returns a new expression /// that can be used in a context that expects a /// `target_type'. /// /// This is different from `ImplicitConversion' in that the /// user defined implicit conversions are excluded. /// </summary> static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr, Type target_type, Location loc) { Type expr_type = expr.Type; Expression e; if (expr.eclass == ExprClass.MethodGroup){ if (!TypeManager.IsDelegateType (target_type)){ return null; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -