static void setBoxing(CompilerContext context, TypeInfo targetType, ExpressionNode expression) { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null || targetType == null) { return; } var type = getType(context, expression); if (type == targetType) { return; } if (isAssignable(context, targetType, expression)) { if (targetType.IsPrimitive) { if (!type.IsPrimitive) { info.BoxingKind = BoxingKind.Unbox; var unboxinMethod = context.TypeSystem.getUnboxingMethod(type); info.BoxingMethod = unboxinMethod; info.OriginalType = info.Type; info.Type = unboxinMethod.ReturnType; } } else if (type.IsPrimitive) { info.BoxingKind = BoxingKind.Box; var boxingMethod = context.TypeSystem.getBoxingMethod((targetType.IsObject) ? type : targetType); info.BoxingMethod = boxingMethod; info.OriginalType = info.Type; info.Type = boxingMethod.ReturnType; } else if (targetType.IsNumeric && type.IsNumeric) { info.BoxingKind = BoxingKind.Unbox; info.BoxingMethod = context.TypeSystem.getUnboxingMethod(type); } } }
static bool isMethod(ExpressionNode argNode) { var info = argNode.getUserData(typeof(ExpressionInfo)); if (info == null || info.Type != null) { return false; } else if (info.IsConstant) { return false; } else if (info.Members != null) { foreach (var member in info.Members) { if (member.MemberKind != MemberKind.Method) { return false; } } } return true; }
static TypeInfo getType(CompilerContext context, ExpressionNode expression) { if (ValidationHelper.isMethod(expression)) { throw context.error(CompileErrorId.UnexpectedMethodReference, expression); } var info = expression.getUserData(typeof(ExpressionInfo)); if (info.Type != null) { return info.Type; } else if (info.IsConstant) { context.ConstantBuilder.buildConstant(expression); return info.Type; } else if (info.Members != null) { foreach (var member in info.Members) { switch (member.MemberKind) { case Field: var field = member.Field; if (field.Value != null) { info.IsConstant = true; info.Value = field.Value; } info.Member = member; info.Type = member.Type; if (!isInDeprecatedContext(context)) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, field)) { context.addWarning(CompileErrorId.DeprecatedField, expression, BytecodeHelper.getDisplayName(field.DeclaringType), field.Name); } } if (context.CodeValidationContext.IsInMethod && context.CodeValidationContext.IsInLambda) { if (!member.IsStatic && expression.ExpressionKind == ExpressionKind.SimpleName) { var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod]; if (typeBuilder.getField("this$0") == null) { typeBuilder.defineField("this$0", context.CurrentType); } } } return member.Type; case Type: info.Member = member; info.Type = member.Type; if (!isInDeprecatedContext(context)) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, info.Type)) { context.addWarning(CompileErrorId.DeprecatedType, expression, BytecodeHelper.getDisplayName(info.Type)); } } return member.Type; case Indexer: case Property: info.Member = member; info.Type = member.Type; if (!isInDeprecatedContext(context)) { if (member.GetAccessor != null) { if (member.SetAccessor == null) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.GetAccessor)) { context.addWarning(CompileErrorId.DeprecatedProperty, expression, BytecodeHelper.getDisplayName(member.DeclaringType), member.Name); } } else { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.GetAccessor) && BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.SetAccessor)) { context.addWarning(CompileErrorId.DeprecatedProperty, expression, BytecodeHelper.getDisplayName(member.DeclaringType), member.Name); } } } else if (member.SetAccessor != null) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.SetAccessor)) { context.addWarning(CompileErrorId.DeprecatedProperty, expression, BytecodeHelper.getDisplayName(member.DeclaringType), member.Name); } } } if (context.CodeValidationContext.IsInMethod && context.CodeValidationContext.IsInLambda) { if (!member.IsStatic && expression.ExpressionKind == ExpressionKind.SimpleName) { var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod]; if (typeBuilder.getField("this$0") == null) { typeBuilder.defineField("this$0", context.CurrentType); } } } return member.Type; case Local: if (context.CodeValidationContext.IsInMethod) { var currentMethod = context.CodeValidationContext.CurrentMethod; var currentType = (TypeBuilder)currentMethod.DeclaringType; if (currentType.FullName.indexOf('#') == -1 && context.CodeValidationContext.IsInLambda) { if (currentMethod != member.Method) { member.IsUsedFromLambda = true; var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod]; context.getLocalField(typeBuilder, (LocalMemberInfo)member); } } } info.Member = member; info.Type = member.Type; return member.Type; default: break; } } if (info.ExtensionMethods != null && info.ExtensionMethods.any()) { return info.Type = info.ExtensionMethods.first().Parameters.first().Type; } } throw new Exception("Internal error line " + (expression.getLine() + 1)); }
private void makeOutputTypeInference(ExpressionNode expression, TypeInfo toType, HashMap<TypeInfo, TypeVariableInfo> typeVariables) { if (expression.ExpressionKind == ExpressionKind.Lambda || BytecodeHelper.isDelegateType(toType) || BytecodeHelper.isExpressionTreeType(toType)) { MethodInfo method = getInvokeMethod(toType); if (method == null) { return; } if (expression.ExpressionKind == ExpressionKind.Lambda) { var lambda = (LambdaExpressionNode)expression; if (lambda.Parameters.size() != method.Parameters.count()) { return; } } var paramTypes = new ArrayList<TypeInfo>(); foreach (var p in method.Parameters) { TypeVariableInfo pinfo = typeVariables[p.Type]; if (pinfo != null) { if (pinfo.fixedType != null) { paramTypes.add(pinfo.fixedType); } else { return; } } else { var t = bindGenericParameters(typeVariables, p.Type); if (t == null) { return; } else { paramTypes.add(t); } } } if (expression.ExpressionKind == ExpressionKind.Lambda) { context.CodeValidationContext.pushLambdaParameters(paramTypes); var success = expressionValidator.handleExpressionNoError(expression, null, true); context.CodeValidationContext.popLambdaParameters(); var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } expression.removeUserData(typeof(ExpressionInfo)); if (success) { makeLowerBoundInference(context.CodeValidationContext.LambdaReturnType, method.ReturnType, typeVariables); } } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } var meth = resolveMethodGroup(info, method, paramTypes); if (meth == null) { makeLowerBoundInference(ValidationHelper.getType(context, expression), toType, typeVariables); } else { makeLowerBoundInference(meth.ReturnType, method.ReturnType, typeVariables); } } } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } makeLowerBoundInference(info.Type, toType, typeVariables); } }
static bool isAssignable(CompilerContext context, TypeInfo type, ExpressionNode expression) { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return !type.IsPrimitive; } var right = getType(context, expression); if (type.isAssignableFrom(right)) { return true; } if (expression.ExpressionKind == ExpressionKind.ArrayInitializer) { if (!type.IsArray) { return false; } foreach (var e in ((ArrayInitializerExpressionNode)expression).Values) { if (!isAssignable(context, type.ElementType, e)) { return false; } } return true; } if (type.IsNumeric && info.IsConstant) { switch (type.NumericTypeKind) { case Byte: { long value; switch (right.TypeKind) { case Char: value = ((Character)info.Value).charValue(); break; case Int: case Long: case Short: value = ((Number)info.Value).longValue(); break; default: return false; } return Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE; } case Char: { long value; switch (right.TypeKind) { case Byte: case Int: case Long: case Short: value = ((Number)info.Value).longValue(); break; default: return false; } return Character.MIN_VALUE <= value && value <= Character.MAX_VALUE; } case Short: { long value; switch (right.TypeKind) { case Byte: return true; case Char: value = ((Character)info.Value).charValue(); break; case Int: case Long: value = ((Number)info.Value).longValue(); break; default: return false; } return Short.MIN_VALUE <= value && value <= Short.MAX_VALUE; } case Int: { long value; switch (right.getTypeKind()) { case Char: value = ((Character)info.Value).charValue(); break; case Byte: case Short: return true; case Long: value = ((Number)info.getValue()).longValue(); break; default: return false; } return Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE; } } } return false; }
private void makeExplicitParameterTypeInference(ExpressionNode expression, TypeInfo toType, HashMap<TypeInfo, TypeVariableInfo> typeVariableInfos) { var method = getInvokeMethod(toType); if (method == null) { return; } if (expression.ExpressionKind == ExpressionKind.Lambda) { var lambda = (LambdaExpressionNode)expression; if (lambda.Parameters.size() != method.Parameters.count()) { return; } } var rinfo = typeVariableInfos[method.ReturnType]; if (rinfo != null) { foreach (var p in method.Parameters) { if (p.Type == method.ReturnType) { continue; } var pinfo = typeVariableInfos[p.Type]; if (pinfo != null) { rinfo.dependencies.add(pinfo.genericParameterType); } } } if (expression.ExpressionKind == ExpressionKind.Lambda) { var lambda = (LambdaExpressionNode)expression; var fromTypes = new ArrayList<TypeInfo>(); var pit = method.Parameters.iterator(); foreach (var p in lambda.Parameters) { var ptype = pit.next().Type; if (p.Type == null) { if (ptype.IsClosed) { fromTypes.add(ptype); } else { return; } } else { fromTypes.add(CompilerHelper.resolveTypeReference(context, context.CurrentType.PackageName, p.Type)); } } context.CodeValidationContext.pushLambdaParameters(fromTypes); bool success = expressionValidator.handleExpressionNoError(expression, null, true); context.CodeValidationContext.popLambdaParameters(); var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } expression.removeUserData(typeof(ExpressionInfo)); if (!success) { return; } var mit = method.Parameters.iterator(); var fit = fromTypes.iterator(); while (mit.hasNext()) { makeExactInference(fit.next(), mit.next().Type, typeVariableInfos); } makeExactInference(context.CodeValidationContext.LambdaReturnType, method.ReturnType, typeVariableInfos); } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } var paramTypes = new ArrayList<TypeInfo>(); foreach (var p in method.Parameters) { paramTypes.add(p.Type); } var meth = resolveMethodGroup(info, method, paramTypes); if (meth == null) { return; } var mit = method.Parameters.iterator(); var cit = meth.Parameters.iterator(); while (mit.hasNext()) { makeExactInference(cit.next().Type, mit.next().Type, typeVariableInfos); } makeExactInference(meth.ReturnType, method.ReturnType, typeVariableInfos); } }
private VarargCompatible isVarargCompatible(ExpressionNode argNode, TypeInfo paramType, bool first) { var ainfo = argNode.getUserData(typeof(ExpressionInfo)); if (ainfo == null) { if (!expressionValidator.handleExpressionNoError(argNode, paramType, true)) { return VarargCompatible.False; } ainfo = argNode.getUserData(typeof(ExpressionInfo)); } if (ainfo == null) { if (paramType.IsPrimitive) { return VarargCompatible.False; } } else if (BytecodeHelper.isDelegateType(paramType)) { if (!resolveDelegate(paramType, argNode, null, null)) { return VarargCompatible.False; } } else if (ValidationHelper.isMethod(argNode)) { return VarargCompatible.False; } else if (paramType != ValidationHelper.getType(context, argNode)) { if (!ValidationHelper.isAssignable(context, paramType, argNode)) { if (first) { if (ValidationHelper.isAssignable(context, paramType.ArrayType, argNode)) { return VarargCompatible.True; } } return VarargCompatible.False; } } return VarargCompatible.TrueExpanded; }
private bool isArgumentCompatible(ExpressionNode argNode, TypeInfo paramType) { var ainfo = argNode.getUserData(typeof(ExpressionInfo)); var cleanInfo = false; if (ainfo == null && argNode.ExpressionKind == ExpressionKind.Lambda) { if (!expressionValidator.handleExpressionNoError(argNode, paramType, true)) { argNode.removeUserData(typeof(ExpressionInfo)); return false; } ainfo = argNode.getUserData(typeof(ExpressionInfo)); cleanInfo = true; } if (ainfo == null) { return !paramType.IsPrimitive; } if (BytecodeHelper.isDelegateType(paramType)) { if (!resolveDelegate(paramType, argNode, null, null)) { if (cleanInfo) { argNode.removeUserData(typeof(ExpressionInfo)); } return false; } } else if (ValidationHelper.isMethod(argNode)) { return false; } else if (paramType != ValidationHelper.getType(context, argNode)) { if (!ValidationHelper.isAssignable(context, paramType, argNode)) { if (cleanInfo) { argNode.removeUserData(typeof(ExpressionInfo)); } return false; } } if (cleanInfo) { argNode.removeUserData(typeof(ExpressionInfo)); } return true; }
bool resolveDelegate(TypeInfo type, ExpressionNode arg, ExpressionInfo targetInfo, SyntaxNode node) { var invokeMethod = getInvokeMethod(type); int nparams = invokeMethod.Parameters.count(); var ainfo = arg.getUserData(typeof(ExpressionInfo)); if (ainfo.Members == null) { return true; } MemberInfo foundMember = null; foreach (var member in ainfo.Members) { switch (member.MemberKind) { case Method: var meth = member.Method; if (meth.Parameters.count() != nparams || meth.IsVarargs != invokeMethod.IsVarargs) { continue; } if (nparams == 0) { if (foundMember != null) { if (node != null) { throw context.error(CompileErrorId.AmbiguousMembers, node, BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method), BytecodeHelper.getDisplayName(foundMember.DeclaringType) + "." + BytecodeHelper.getDisplayName(foundMember.Method)); } else { return false; } } foundMember = member; ainfo.Member = member; if (meth.IsExcludedFromCompilation || CompilerHelper.shouldIgnoreCalls(context, meth)) { if (node != null) { throw context.error(CompileErrorId.NotGeneratedMethodUsage, node, BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method)); } else { return false; } } if (targetInfo != null) { targetInfo.Type = type; targetInfo.Method = meth; } continue; } var it1 = meth.Parameters.iterator(); var it2 = invokeMethod.Parameters.iterator(); var sameParams = true; while (it1.hasNext()) { if (it1.next().Type != it2.next().Type) { sameParams = false; break; } } if (sameParams) { if (foundMember != null) { if (node != null) { throw context.error(CompileErrorId.AmbiguousMembers, node, BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method), BytecodeHelper.getDisplayName(foundMember.DeclaringType) + "." + foundMember.Name); } else { return false; } } foundMember = member; ainfo.Member = member; if (targetInfo != null) { targetInfo.Type = type; targetInfo.Method = meth; } continue; } break; case Local: ainfo.Member = member; return true; case Field: case Property: foundMember = member; ainfo.Member = member; break; } } if (foundMember != null) { return true; } if (node != null) { throw context.error(CompileErrorId.NoEligibleOverload, node, ainfo.Members.first().Name); } else { return false; } }
private BetterConversionResult getBetterConversionFromExpression(TypeInfo leftType, TypeInfo rightType, ExpressionNode expression) { if (leftType == rightType) { return BetterConversionResult.Neither; } if (expression.ExpressionKind == ExpressionKind.Lambda) { var leftMethod = getInvokeMethod(leftType); var rightMethod = getInvokeMethod(rightType); var leftReturnType = leftMethod.ReturnType; var rightReturnType = rightMethod.ReturnType; var lit = leftMethod.Parameters.iterator(); var rit = rightMethod.Parameters.iterator(); List<TypeInfo> paramTypes = null; while (lit.hasNext()) { var lt = lit.next().Type; var rt = rit.next().Type; if (lt != rt) { return BetterConversionResult.Neither; } if (paramTypes == null) { paramTypes = new ArrayList<TypeInfo>(); } paramTypes.add(lt); } if (paramTypes != null) { context.CodeValidationContext.pushLambdaParameters(paramTypes); } else { context.CodeValidationContext.pushLambdaParameters(Collections.emptyList<TypeInfo>()); } expressionValidator.handleExpressionNoError(expression, null, true); context.CodeValidationContext.popLambdaParameters(); var info = expression.getUserData(typeof(ExpressionInfo)); expression.removeUserData(typeof(ExpressionInfo)); if (info != null) { if (leftReturnType == context.TypeSystem.VoidType) { return BetterConversionResult.RightIsBetter; } if (rightReturnType == context.TypeSystem.VoidType) { return BetterConversionResult.LeftIsBetter; } return getBetterConversionFromType(leftReturnType, rightReturnType, context.CodeValidationContext.LambdaReturnType); } return BetterConversionResult.Neither; } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return BetterConversionResult.Neither; } return getBetterConversionFromType(leftType, rightType, ValidationHelper.getType(context, expression)); } }