Example #1
0
    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;
    }
Example #2
0
    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);
    }
Example #3
0
 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;
     }
   }
 }