@@ -83,22 +83,30 @@ private Expression ParseExpressionSegment()
8383 // MSDN C# "Operator precedence and associativity"
8484 // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/
8585
86- return ParseAssignement ( ) ;
86+ return ParseAssignment ( ) ;
8787 }
8888
8989 // = operator
90- private Expression ParseAssignement ( )
90+ private Expression ParseAssignment ( )
9191 {
9292 var left = ParseConditional ( ) ;
9393 if ( _token . id == TokenId . Equal )
9494 {
9595 if ( ! _arguments . Settings . AssignmentOperators . HasFlag ( AssignmentOperators . AssignmentEqual ) )
9696 throw new AssignmentOperatorDisabledException ( "=" , _token . pos ) ;
9797
98+ if ( ! IsWritable ( left ) )
99+ throw CreateParseException ( _token . pos , ErrorMessages . ExpressionMustBeWritable ) ;
100+
98101 NextToken ( ) ;
99- var right = ParseAssignement ( ) ;
100- CheckAndPromoteOperands ( typeof ( ParseSignatures . IEqualitySignatures ) , ref left , ref right ) ;
101- left = Expression . Assign ( left , right ) ;
102+
103+ var right = ParseAssignment ( ) ;
104+ var promoted = PromoteExpression ( right , left . Type , true ) ;
105+ if ( promoted == null )
106+ throw CreateParseException ( _token . pos , ErrorMessages . CannotConvertValue ,
107+ GetTypeName ( right . Type ) , GetTypeName ( left . Type ) ) ;
108+
109+ left = Expression . Assign ( left , promoted ) ;
102110 }
103111 return left ;
104112 }
@@ -1088,12 +1096,17 @@ private Expression ParseElementAccess(Expression expr)
10881096 NextToken ( ) ;
10891097 if ( expr . Type . IsArray )
10901098 {
1091- if ( expr . Type . GetArrayRank ( ) != 1 || args . Length != 1 )
1092- throw CreateParseException ( errorPos , ErrorMessages . CannotIndexMultiDimArray ) ;
1093- var index = PromoteExpression ( args [ 0 ] , typeof ( int ) , true ) ;
1094- if ( index == null )
1095- throw CreateParseException ( errorPos , ErrorMessages . InvalidIndex ) ;
1096- return Expression . ArrayIndex ( expr , index ) ;
1099+ if ( expr . Type . GetArrayRank ( ) != args . Length )
1100+ throw CreateParseException ( errorPos , ErrorMessages . IncorrectNumberOfIndexes ) ;
1101+
1102+ for ( int i = 0 ; i < args . Length ; i ++ )
1103+ {
1104+ args [ i ] = PromoteExpression ( args [ i ] , typeof ( int ) , true ) ;
1105+ if ( args [ i ] == null )
1106+ throw CreateParseException ( errorPos , ErrorMessages . InvalidIndex ) ;
1107+ }
1108+
1109+ return Expression . ArrayAccess ( expr , args ) ;
10971110 }
10981111
10991112 var applicableMethods = FindIndexer ( expr . Type , args ) ;
@@ -1109,9 +1122,8 @@ private Expression ParseElementAccess(Expression expr)
11091122 GetTypeName ( expr . Type ) ) ;
11101123 }
11111124
1112- var method = applicableMethods [ 0 ] ;
1113-
1114- return Expression . Call ( expr , ( MethodInfo ) method . MethodBase , method . PromotedParameters ) ;
1125+ var indexer = ( IndexerData ) applicableMethods [ 0 ] ;
1126+ return Expression . Property ( expr , indexer . Indexer , indexer . PromotedParameters ) ;
11151127 }
11161128
11171129 private static bool IsNullableType ( Type type )
@@ -1266,10 +1278,9 @@ private MethodData[] FindIndexer(Type type, Expression[] args)
12661278 MemberInfo [ ] members = t . GetDefaultMembers ( ) ;
12671279 if ( members . Length != 0 )
12681280 {
1269- IEnumerable < MethodBase > methods = members .
1281+ IEnumerable < MethodData > methods = members .
12701282 OfType < PropertyInfo > ( ) .
1271- Select ( p => ( MethodBase ) p . GetGetMethod ( ) ) .
1272- Where ( m => m != null ) ;
1283+ Select ( p => ( MethodData ) new IndexerData ( p ) ) ;
12731284
12741285 var applicableMethods = FindBestMethod ( methods , args ) ;
12751286 if ( applicableMethods . Length > 0 )
@@ -1316,9 +1327,13 @@ private static void AddInterface(List<Type> types, Type type)
13161327 }
13171328
13181329 private static MethodData [ ] FindBestMethod ( IEnumerable < MethodBase > methods , Expression [ ] args )
1330+ {
1331+ return FindBestMethod ( methods . Select ( MethodData . Gen ) , args ) ;
1332+ }
1333+
1334+ private static MethodData [ ] FindBestMethod ( IEnumerable < MethodData > methods , Expression [ ] args )
13191335 {
13201336 var applicable = methods .
1321- Select ( m => new MethodData { MethodBase = m , Parameters = m . GetParameters ( ) } ) .
13221337 Where ( m => CheckIfMethodIsApplicableAndPrepareIt ( m , args ) ) .
13231338 ToArray ( ) ;
13241339 if ( applicable . Length > 1 )
@@ -1417,7 +1432,7 @@ private static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Exp
14171432
14181433 method . PromotedParameters = promotedArgs . ToArray ( ) ;
14191434
1420- if ( method . MethodBase . IsGenericMethodDefinition &&
1435+ if ( method . MethodBase != null && method . MethodBase . IsGenericMethodDefinition &&
14211436 method . MethodBase is MethodInfo )
14221437 {
14231438 var methodInfo = ( MethodInfo ) method . MethodBase ;
@@ -1626,6 +1641,30 @@ private static bool IsCompatibleWith(Type source, Type target)
16261641 return false ;
16271642 }
16281643
1644+ private static bool IsWritable ( Expression expression )
1645+ {
1646+ switch ( expression . NodeType )
1647+ {
1648+ case ExpressionType . Index :
1649+ PropertyInfo indexer = ( ( IndexExpression ) expression ) . Indexer ;
1650+ return indexer == null || indexer . CanWrite ;
1651+ case ExpressionType . MemberAccess :
1652+ MemberInfo member = ( ( MemberExpression ) expression ) . Member ;
1653+ var prop = member as PropertyInfo ;
1654+ if ( prop != null )
1655+ return prop . CanWrite ;
1656+ else
1657+ {
1658+ var field = ( FieldInfo ) member ;
1659+ return ! ( field . IsInitOnly || field . IsLiteral ) ;
1660+ }
1661+ case ExpressionType . Parameter :
1662+ return true ;
1663+ }
1664+
1665+ return false ;
1666+ }
1667+
16291668 // from http://stackoverflow.com/a/1075059/209727
16301669 private static Type FindAssignableGenericType ( Type givenType , Type genericTypeDefinition )
16311670 {
@@ -2156,6 +2195,43 @@ private class MethodData
21562195 public ParameterInfo [ ] Parameters ;
21572196 public Expression [ ] PromotedParameters ;
21582197 public bool HasParamsArray ;
2198+
2199+ public static MethodData Gen ( MethodBase method )
2200+ {
2201+ return new MethodData
2202+ {
2203+ MethodBase = method ,
2204+ Parameters = method . GetParameters ( )
2205+ } ;
2206+ }
2207+ }
2208+
2209+ private class IndexerData : MethodData
2210+ {
2211+ public readonly PropertyInfo Indexer ;
2212+
2213+ public IndexerData ( PropertyInfo indexer )
2214+ {
2215+ Indexer = indexer ;
2216+
2217+ var method = indexer . GetGetMethod ( ) ;
2218+ if ( method != null )
2219+ {
2220+ Parameters = method . GetParameters ( ) ;
2221+ }
2222+ else
2223+ {
2224+ method = indexer . GetSetMethod ( ) ;
2225+ Parameters = RemoveLast ( method . GetParameters ( ) ) ;
2226+ }
2227+ }
2228+
2229+ private static T [ ] RemoveLast < T > ( T [ ] array )
2230+ {
2231+ T [ ] result = new T [ array . Length - 1 ] ;
2232+ Array . Copy ( array , 0 , result , 0 , result . Length ) ;
2233+ return result ;
2234+ }
21592235 }
21602236 }
21612237}
0 commit comments