From b5bfb7997b9cc4ad5cd8dc13d667a397f724d307 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Wed, 16 Jan 2019 12:07:40 +0100 Subject: [PATCH] Better handling of C# function parameter type checking --- .../InternalFunctionVariableSymbol.cs | 27 +++++++++++++++++++ .../BoundTypes/UserDataBoundTypeDefinition.cs | 22 ++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Upsilon/Binder/VariableSymbols/InternalFunctionVariableSymbol.cs b/Upsilon/Binder/VariableSymbols/InternalFunctionVariableSymbol.cs index 08d3485..177219a 100644 --- a/Upsilon/Binder/VariableSymbols/InternalFunctionVariableSymbol.cs +++ b/Upsilon/Binder/VariableSymbols/InternalFunctionVariableSymbol.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Immutable; using System.Linq; +using Upsilon.BoundTypes; using Type = Upsilon.BaseTypes.Type; namespace Upsilon.Binder.VariableSymbols @@ -16,8 +17,17 @@ namespace Upsilon.Binder.VariableSymbols Name = name; } + public InternalFunctionParameter(string name, Type type, string[] expectedUserData, bool isOptional) + { + ValidTypes = type; + ExpectedUserData = expectedUserData; + IsOptional = isOptional; + Name = name; + } + public string Name { get; } public Type ValidTypes { get; } + public string[] ExpectedUserData { get; } public bool IsOptional { get; } } @@ -56,6 +66,23 @@ namespace Upsilon.Binder.VariableSymbols $"Expected one of the following: {functionParameter.ValidTypes.ToString()}, got: '{callingParameter.Type}'", callingParameter); } + + if (functionParameter.ValidTypes.HasFlag(Type.UserData)) + { + var variable = Binder.ResolveVariable(callingParameter, null); + if (variable != null && variable.Type == Type.UserData) + { + var parent = + (UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition; + if (functionParameter.ExpectedUserData != null && !functionParameter.ExpectedUserData.Contains(parent.Name)) + { + return (false, + $"Unexpected variable passed to internal function at variable {i + 1}. " + + $"Expected to be the following: {string.Join(", ", functionParameter.ExpectedUserData)}, got: '{parent.Name}'", + callingParameter); + } + } + } } return (true, null, null); diff --git a/Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs b/Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs index 5666d5d..c4e91a0 100644 --- a/Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs +++ b/Upsilon/BoundTypes/UserDataBoundTypeDefinition.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Reflection; using Upsilon.BaseTypes; using Upsilon.Binder; +using Upsilon.Binder.VariableSymbols; using Upsilon.StandardLibraries; using Type = Upsilon.BaseTypes.Type; @@ -135,7 +136,8 @@ namespace Upsilon.BoundTypes Properties.Add(valueName, new UserDataBoundProperty() { Name = valueName, - Type = Type.UserData + Type = Type.UserData, + ActualType = name }); } } @@ -185,6 +187,24 @@ namespace Upsilon.BoundTypes $"Expected one of the following: {functionParameter.Type.ToString()}, got: '{callingParameter.Type}'", callingParameter); } + + if (functionParameter.Type.HasFlag(Type.UserData)) + { + var variable = Binder.Binder.ResolveVariable(callingParameter, null); + if (variable != null && variable.Type == Type.UserData) + { + var parent = + (UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition; + if (functionParameter.ActualType != null && + !string.Equals(functionParameter.ActualType, parent.Name, StringComparison.InvariantCultureIgnoreCase)) + { + return (false, + $"Unexpected variable passed to internal function at variable {i + 1}. " + + $"Expected to be the following: {functionParameter.ActualType}, got: '{parent.Name}'", + callingParameter); + } + } + } } return (true, null, null);