public virtual Expression ImplicitCoercion(Expression source, TypeNode targetType, TypeViewer typeViewer){ TypeNode originalTargetType = targetType; if (targetType == null || targetType.Name == Looker.NotFound) return source; if (source == null) return null; //HS D if (source is Hole) { source.Type = targetType; return source; } //HS D if (source is LambdaHole) { if (targetType == SystemTypes.Boolean) source = new LambdaHole(source, new Literal(0), NodeType.Ge, source.SourceContext); source.Type = targetType; return source; } Literal sourceLit = source as Literal; if (sourceLit != null && sourceLit.Value is TypeNode){ this.HandleError(source, Error.TypeInVariableContext, this.GetTypeName((TypeNode)sourceLit.Value), "class", "variable"); return null; } //Ignore parentheses if (source.NodeType == NodeType.Parentheses){ UnaryExpression uex = (UnaryExpression)source; uex.Operand = this.ImplicitCoercion(uex.Operand, targetType, typeViewer); if (uex.Operand == null) return null; uex.Type = uex.Operand.Type; return uex; } bool targetIsNonNullType = this.IsNonNullType(targetType); targetType = TypeNode.StripModifier(targetType, SystemTypes.NonNullType); targetType = TypeNode.StripModifier(targetType, SystemTypes.NullableType); //TODO: handle SkipCheck and EnforceCheck //Special case for closure expressions if (source.NodeType == NodeType.AnonymousNestedFunction) return this.CoerceAnonymousNestedFunction((AnonymousNestedFunction)source, targetType, false, typeViewer); TypeNode sourceType = source.Type; if (sourceType == null) sourceType = SystemTypes.Object; bool sourceIsNonNullType = this.IsNonNullType(source.Type); sourceType = TypeNode.StripModifier(sourceType, SystemTypes.NonNullType); sourceType = TypeNode.StripModifier(sourceType, SystemTypes.NullableType); if (sourceType == SystemTypes.String && !sourceIsNonNullType && source is Literal) sourceIsNonNullType = ((Literal)source).Value != null; if (this.currentParameter != null && targetType is Reference){ UnaryExpression uex = source as UnaryExpression; if (uex != null){ if (sourceIsNonNullType && !targetIsNonNullType){ string ttypeName = this.GetTypeName(targetType); string stypeName = this.GetTypeName(source.Type); this.HandleError(source, Error.NoImplicitCoercion, stypeName, ttypeName); return null; } if (!sourceIsNonNullType && targetIsNonNullType){ string ttypeName = this.GetTypeName(targetType); string stypeName = this.GetTypeName(source.Type); this.HandleError(source, Error.NoImplicitCoercion, stypeName, ttypeName); return null; } if (uex.NodeType == NodeType.OutAddress){ if ((this.currentParameter.Flags & ParameterFlags.Out) == 0){ this.currentParameter.Flags |= ParameterFlags.Out; string stypeName = this.GetTypeName(sourceType); this.currentParameter.Flags &= ~ParameterFlags.Out; this.HandleError(source, Error.NoImplicitCoercion, stypeName, this.GetTypeName(targetType)); return null; } }else if (uex.NodeType == NodeType.RefAddress){ if ((this.currentParameter.Flags & ParameterFlags.Out) != 0){ this.currentParameter.Flags &= ~ParameterFlags.Out; string stypeName = this.GetTypeName(sourceType); this.currentParameter.Flags |= ParameterFlags.Out; this.HandleError(source, Error.NoImplicitCoercion, stypeName, this.GetTypeName(targetType)); return null; } } } } Expression result = this.StandardImplicitCoercion(source, sourceIsNonNullType, sourceType, targetIsNonNullType, targetType, originalTargetType, typeViewer); if (result != null) return result; Method coercion = this.UserDefinedImplicitCoercionMethod(source, sourceType, targetType, true, typeViewer); if (coercion != null){ if (this.IsNullableType(targetType) && this.IsNullableType(sourceType) && !this.IsNullableType(coercion.Parameters[0].Type)) return this.CoerceWithLiftedCoercion(source, sourceType, targetType, coercion, false, typeViewer); ExpressionList args = new ExpressionList(1); args.Add(this.ImplicitCoercion(source, coercion.Parameters[0].Type, typeViewer)); return this.ImplicitCoercion(new MethodCall(new MemberBinding(null, coercion), args, NodeType.Call, coercion.ReturnType, source.SourceContext), targetType, typeViewer); } if (sourceType == SystemTypes.Type && source is Literal) this.HandleError(source, Error.TypeInVariableContext, this.GetTypeName((TypeNode)((Literal)source).Value), "class", "variable"); else if (this.IsNullableType(sourceType) && this.IsNullableType(targetType) && this.ImplicitCoercionFromTo(this.RemoveNullableWrapper(sourceType), this.RemoveNullableWrapper(targetType))) { TypeNode usType = this.RemoveNullableWrapper(sourceType); TypeNode utType = this.RemoveNullableWrapper(targetType); Local tempSrc = new Local(sourceType); Local tempTar = new Local(targetType); StatementList statements = new StatementList(); BlockExpression result1 = new BlockExpression(new Block(statements)); statements.Add(new AssignmentStatement(tempSrc, source)); Method hasValue = sourceType.GetMethod(StandardIds.getHasValue); Method getValueOrDefault = sourceType.GetMethod(StandardIds.GetValueOrDefault); Method ctor = targetType.GetMethod(StandardIds.Ctor, utType); Block pushValue = new Block(); Block done = new Block(); Expression tempHasValue = new MethodCall(new MemberBinding(new UnaryExpression(tempSrc, NodeType.AddressOf), hasValue), null); tempHasValue.Type = SystemTypes.Boolean; statements.Add(new Branch(tempHasValue, pushValue)); statements.Add(new AssignmentStatement(new AddressDereference(new UnaryExpression(tempTar, NodeType.AddressOf), targetType), new Literal(null, CoreSystemTypes.Object))); statements.Add(new Branch(null, done)); statements.Add(pushValue); Expression value = new MethodCall(new MemberBinding(new UnaryExpression(tempSrc, NodeType.AddressOf), getValueOrDefault), null); value.Type = usType; value = this.ImplicitCoercion(value, utType); Construct cons = new Construct(new MemberBinding(null, ctor), new ExpressionList(value)); result1.Type = ctor.DeclaringType; statements.Add(new AssignmentStatement(tempTar, cons)); statements.Add(done); statements.Add(new ExpressionStatement(tempTar)); return result1; }else this.HandleError(source, Error.NoImplicitCoercion, this.GetTypeName(sourceType), this.GetTypeName(originalTargetType)); return null; }
public virtual Expression CoerceShortCircuitOps(BinaryExpression binaryExpression, Expression opnd1, Expression opnd2, Literal lit1, Literal lit2, TypeNode opnd1Type, TypeNode opnd2Type) { TypeNode unifiedType = binaryExpression.Type; //HS D if (opnd1 is Hole || opnd2 is Hole) { if (opnd1 is Hole) { ((Hole)opnd1).Type = unifiedType; binaryExpression.Operand1 = opnd1; } if (opnd2 is Hole) { ((Hole)opnd2).Type = unifiedType; binaryExpression.Operand2 = opnd2; } return binaryExpression; } //HS D if (opnd1 is LambdaHole || opnd2 is LambdaHole) { if (opnd1 is LambdaHole) { if (unifiedType == SystemTypes.Boolean) opnd1 = new LambdaHole(opnd1, new Literal(0), NodeType.Ge, opnd1.SourceContext); opnd1.Type = unifiedType; binaryExpression.Operand1 = opnd1; } if (opnd2 is LambdaHole) { if (unifiedType == SystemTypes.Boolean) opnd2 = new LambdaHole(opnd2, new Literal(0), NodeType.Ge, opnd2.SourceContext); opnd2.Type = unifiedType; binaryExpression.Operand2 = opnd2; } return binaryExpression; } MethodCall mcall = opnd2 as MethodCall; if (mcall != null && opnd1 is Local) { MemberBinding mb = mcall.Callee as MemberBinding; Method oper = mb == null ? null : mb.BoundMember as Method; if (oper != null && (oper.Name.UniqueIdKey == StandardIds.opBitwiseAnd.UniqueIdKey || oper.Name.UniqueIdKey == StandardIds.opBitwiseOr.UniqueIdKey)) { //Found a user defined overload for & or |, check signature and check for presence of op_True and op_False unifiedType = oper.ReturnType; if (unifiedType != oper.DeclaringType || unifiedType != oper.Parameters[0].Type || unifiedType != oper.Parameters[1].Type) { this.HandleError(binaryExpression, Error.BadBoolOp, this.GetMethodSignature(oper)); return null; } if (unifiedType == null) return null; if (this.GetTypeView(unifiedType).GetOpTrue() != null) return CoercedBinaryExpression(binaryExpression, opnd1, opnd2, unifiedType); this.HandleError(binaryExpression, Error.MustHaveOpTF, this.GetTypeName(unifiedType)); return null; } } if (!this.typeSystem.ImplicitCoercionFromTo(opnd1Type, SystemTypes.Boolean, this.TypeViewer) || !this.typeSystem.ImplicitCoercionFromTo(opnd2Type, SystemTypes.Boolean, this.TypeViewer)) { this.ReportBadOperands(binaryExpression, Error.BadBinaryOps, lit1, lit2, opnd1Type, opnd2Type); return null; } unifiedType = SystemTypes.Boolean; return this.CoercedBinaryExpression(binaryExpression, opnd1, opnd2, unifiedType); }
private Expression ParseIndexerCallOrSelector(Expression expression, TokenSet followers){ TokenSet followersOrContinuers = followers|Token.LeftBracket|Token.LeftParenthesis|Token.Dot; for(;;){ switch (this.currentToken){ case Token.LeftBracket: SourceContext lbCtx = this.scanner.CurrentSourceContext; this.GetNextToken(); if (this.insideModifiesClause && this.currentToken == Token.Multiply){ // Handle code such as // // modifies myArray[*]; // // which means that the method may modify all elements of myArray. int savedStartPos = this.scanner.startPos; int savedEndPos = this.scanner.endPos; this.GetNextToken(); if (this.currentToken == Token.RightBracket){ SourceContext sctxt = this.scanner.CurrentSourceContext; sctxt.StartPos = lbCtx.StartPos; this.GetNextToken(); return new ModifiesArrayClause(expression, sctxt); } this.scanner.startPos = savedStartPos; this.scanner.endPos = savedEndPos; } int endCol; ExpressionList indices = this.ParseIndexList(followersOrContinuers, lbCtx, out endCol); Indexer indexer = new Indexer(expression, indices); indexer.SourceContext = expression.SourceContext; indexer.SourceContext.EndPos = endCol; indexer.ArgumentListIsIncomplete = this.scanner.GetChar(endCol-1) != ']'; expression = indexer; break; case Token.LessThan: SourceContext ltCtx = this.scanner.CurrentSourceContext; ScannerState ss = this.scanner.state; int arity; TypeNodeList typeArguments = this.ParseTypeArguments(true, false, followers|Token.LeftParenthesis, out endCol, out arity); if (typeArguments == null || (typeArguments.Count > 1 && Parser.TypeArgumentListNonFollower[this.currentToken])) { this.scanner.endPos = ltCtx.StartPos; this.scanner.state = ss; this.currentToken = Token.None; this.GetNextToken(); return expression; } TemplateInstance instance = new TemplateInstance(expression, typeArguments); instance.TypeArgumentExpressions = typeArguments == null ? null : typeArguments.Clone(); instance.SourceContext = expression.SourceContext; instance.SourceContext.EndPos = endCol; expression = instance; break; case Token.LeftParenthesis: SourceContext lpCtx = this.scanner.CurrentSourceContext; this.GetNextToken(); ExpressionList arguments = this.ParseArgumentList(followersOrContinuers, lpCtx, out endCol); if (expression == null) return null; if (expression is Identifier && arguments.Count == 1 && ((Identifier)expression).Name == "old" && InEnsuresContext){ OldExpression old = new OldExpression(arguments[0]); typeArguments = null; old.SourceContext = expression.SourceContext; old.SourceContext.EndPos = endCol; expression = old; break; } if (expression is TemplateInstance) ((TemplateInstance)expression).IsMethodTemplate = true; //HS D: a lambda hole... : make a linear comb of args for hole if (expression is Hole) { SourceContext sctx = expression.SourceContext; Expression res = expression; if (arguments.Count > 0) { res = new BinaryExpression(expression, arguments[0], NodeType.Mul, sctx); for (int i = 1; i < arguments.Count; i++) res = new BinaryExpression(res, new BinaryExpression(new Hole(sctx), arguments[i], NodeType.Mul, sctx), NodeType.Add, sctx); res = new LambdaHole(res, new Hole(sctx), NodeType.Add, sctx); } expression = res; break; } MethodCall mcall = new MethodCall(expression, arguments); typeArguments = null; mcall.GiveErrorIfSpecialNameMethod = true; mcall.SourceContext = expression.SourceContext; mcall.SourceContext.EndPos = endCol; mcall.ArgumentListIsIncomplete = this.scanner.GetChar(endCol-1) != ')'; expression = mcall; break; case Token.LeftBrace: if (this.compatibilityOn || this.scanner.TokenIsFirstAfterLineBreak) goto default; Expression quant = this.ParseComprehension(followers); if (quant == null) { break; } Block argBlock = new Block(new StatementList(new ExpressionStatement(quant)),quant.SourceContext, this.insideCheckedBlock, this.insideUncheckedBlock, this.inUnsafeCode); argBlock.IsUnsafe = this.inUnsafeCode; argBlock.SourceContext = quant.SourceContext; ExpressionList arguments2 = new ExpressionList(new AnonymousNestedFunction(new ParameterList(0), argBlock, quant.SourceContext)); MethodCall mcall2 = new MethodCall(expression, arguments2); typeArguments = null; mcall2.GiveErrorIfSpecialNameMethod = true; mcall2.SourceContext = expression.SourceContext; mcall2.SourceContext.EndPos = this.scanner.endPos; expression = mcall2; break; case Token.Dot: expression = this.ParseQualifiedIdentifier(expression, followersOrContinuers); break; case Token.RealLiteral: string tokStr = this.scanner.GetTokenSource(); if (this.insideModifiesClause && tokStr == ".0") { // this case is here only for parsing ".0" while parsing a modifies clause // e.g., "modifies this.0;" this.GetNextToken(); // eat the ".0" return new ModifiesNothingClause(expression, this.scanner.CurrentSourceContext); } else { return expression; } case Token.Arrow: if (!this.allowUnsafeCode){ this.HandleError(Error.IllegalUnsafe); this.allowUnsafeCode = true; } this.currentToken = Token.Dot; AddressDereference ad = new AddressDereference(); ad.Address = expression; ad.ExplicitOperator = AddressDereference.ExplicitOp.Arrow; ad.SourceContext = expression.SourceContext; expression = this.ParseQualifiedIdentifier(ad, followersOrContinuers); break; default: return expression; } } }