diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs index 72b95dc7ff..a4a8efca62 100644 --- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs +++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs @@ -234,10 +234,14 @@ namespace Grunwald.BooBinding.CodeCompletion // TODO: Type inference IReturnType CreateReturnType(AST.Method node, IMethod method) { + if (node.ReturnType == null) + return new InferredReturnType(node.Body); return CreateReturnType(node.ReturnType, method); } IReturnType CreateReturnType(AST.Property property) { + if (property.Type == null && property.Getter != null && property.Getter.Body != null) + return new InferredReturnType(property.Getter.Body); return CreateReturnType(property.Type); } diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/InferredReturnType.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/InferredReturnType.cs index 6907ba8853..234e0b7d9c 100644 --- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/InferredReturnType.cs +++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/InferredReturnType.cs @@ -18,29 +18,76 @@ namespace Grunwald.BooBinding.CodeCompletion public class InferredReturnType : ProxyReturnType { Expression expression; + Block block; + IReturnType cachedType; public InferredReturnType(Expression expression) { + if (expression == null) throw new ArgumentNullException("expression"); this.expression = expression; } - bool needInfer = true; - IReturnType cachedType; + public InferredReturnType(Block block) + { + if (block == null) throw new ArgumentNullException("block"); + this.block = block; + } + + public override bool IsDefaultReturnType { + get { + IReturnType baseType = BaseType; + return (baseType != null) ? baseType.IsDefaultReturnType : false; + } + } public override IReturnType BaseType { get { - if (needInfer) { - needInfer = false; + // clear up references to method/expression after the type has been resolved + if (block != null) { + GetReturnTypeVisitor v = new GetReturnTypeVisitor(); + v.Visit(block); + block = null; + if (v.noReturnStatement) + cachedType = ReflectionReturnType.Void; + else if (v.result is NullReturnType) + cachedType = ReflectionReturnType.Object; + else + cachedType = v.result; + } else if (expression != null) { cachedType = new BooResolver().GetTypeOfExpression(expression); + expression = null; } return cachedType; } } - public override bool IsDefaultReturnType { - get { - IReturnType baseType = BaseType; - return (baseType != null) ? baseType.IsDefaultReturnType : false; + class GetReturnTypeVisitor : DepthFirstVisitor + { + public IReturnType result; + public bool noReturnStatement = true; + + public override void OnReturnStatement(ReturnStatement node) + { + noReturnStatement = false; + if (node.Expression == null) { + result = ReflectionReturnType.Void; + } else { + result = new BooResolver().GetTypeOfExpression(node.Expression); + } + } + + public override void OnYieldStatement(YieldStatement node) + { + noReturnStatement = false; + result = ReflectionReturnType.CreatePrimitive(typeof(System.Collections.IEnumerable)); + } + + public override bool Visit(Node node) + { + if (result != null && !(result is NullReturnType)) + return false; + else + return base.Visit(node); } } } diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs index eaccdfd0d5..88072f58eb 100644 --- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs +++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs @@ -369,6 +369,46 @@ namespace Grunwald.BooBinding.CodeCompletion } #endregion + public override void OnBinaryExpression(BinaryExpression node) + { + switch (node.Operator) { + case BinaryOperatorType.GreaterThan: + case BinaryOperatorType.GreaterThanOrEqual: + case BinaryOperatorType.Inequality: + case BinaryOperatorType.LessThan: + case BinaryOperatorType.LessThanOrEqual: + case BinaryOperatorType.Match: + case BinaryOperatorType.Member: + case BinaryOperatorType.NotMatch: + case BinaryOperatorType.NotMember: + case BinaryOperatorType.Or: + case BinaryOperatorType.And: + case BinaryOperatorType.ReferenceEquality: + case BinaryOperatorType.ReferenceInequality: + case BinaryOperatorType.TypeTest: + MakeResult(ReflectionReturnType.Bool); + break; + default: + if (node.Left == null) { + if (node.Right == null) { + resolveResult = null; + } else { + node.Right.Accept(this); + } + return; + } else if (node.Right == null) { + node.Left.Accept(this); + return; + } + node.Left.Accept(this); + IReturnType left = (resolveResult != null) ? resolveResult.ResolvedType : null; + node.Right.Accept(this); + IReturnType right = (resolveResult != null) ? resolveResult.ResolvedType : null; + MakeResult(MemberLookupHelper.GetCommonType(left, right)); + break; + } + } + protected override void OnError(Node node, Exception error) { MessageService.ShowError(error, "ResolveVisitor: error processing " + node); diff --git a/src/Main/Base/Project/Src/Dom/Implementations/NullReturnType.cs b/src/Main/Base/Project/Src/Dom/Implementations/NullReturnType.cs index 35903dbd77..6b414cb813 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/NullReturnType.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/NullReturnType.cs @@ -11,8 +11,8 @@ using ICSharpCode.Core; namespace ICSharpCode.SharpDevelop.Dom { - /// The type of the 'null'/'nothing' literal. [Serializable] + /// The type of the 'null'/'nothing' literal. public sealed class NullReturnType : AbstractReturnType { public static readonly NullReturnType Instance = new NullReturnType(); diff --git a/src/Main/Base/Project/Src/Dom/MemberLookupHelper.cs b/src/Main/Base/Project/Src/Dom/MemberLookupHelper.cs index 228646f5b1..24c8c039f2 100644 --- a/src/Main/Base/Project/Src/Dom/MemberLookupHelper.cs +++ b/src/Main/Base/Project/Src/Dom/MemberLookupHelper.cs @@ -671,5 +671,19 @@ namespace ICSharpCode.SharpDevelop.Dom } } #endregion + + /// + /// Gets the common base type of a and b. + /// + public static IReturnType GetCommonType(IReturnType a, IReturnType b) + { + if (a == null) return b; + if (b == null) return a; + if (ConversionExists(a, b)) + return b; + if (ConversionExists(b, a)) + return a; + return ReflectionReturnType.Object; + } } } diff --git a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/TypeVisitor.cs b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/TypeVisitor.cs index 2eea46f108..bae24230c1 100644 --- a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/TypeVisitor.cs +++ b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/TypeVisitor.cs @@ -60,7 +60,8 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver case BinaryOperatorType.GreaterThanOrEqual: return ReflectionReturnType.Bool; default: - return binaryOperatorExpression.Left.AcceptVisitor(this, data); + return MemberLookupHelper.GetCommonType(binaryOperatorExpression.Left.AcceptVisitor(this, data) as IReturnType, + binaryOperatorExpression.Right.AcceptVisitor(this, data) as IReturnType); } }