diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs index 38346a6e0..d67c9a012 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs @@ -90,7 +90,7 @@ public IMember GetValueFromLambda(LambdaExpression expr) { public IMember GetValueFromClassCtor(IPythonClassType cls, CallExpression expr) { SymbolTable.Evaluate(cls.ClassDefinition); // Determine argument types - var args = ArgumentSet.Empty; + var args = ArgumentSet.Empty(expr, this); var init = cls.GetMember(@"__init__"); if (init != null) { using (OpenScope(cls.DeclaringModule, cls.ClassDefinition, out _)) { @@ -109,7 +109,7 @@ private IMember GetValueFromBound(IPythonBoundType t, CallExpression expr) { case IPythonFunctionType fn: return GetValueFromFunctionType(fn, t.Self, expr); case IPythonPropertyType p: - return GetValueFromProperty(p, t.Self); + return GetValueFromProperty(p, t.Self, expr); case IPythonIteratorType _ when t.Self is IPythonCollection seq: return seq.GetIterator(); } @@ -202,10 +202,10 @@ public IMember GetValueFromFunctionType(IPythonFunctionType fn, IPythonInstance return UnknownType; } - private IMember GetValueFromProperty(IPythonPropertyType p, IPythonInstance instance) { + private IMember GetValueFromProperty(IPythonPropertyType p, IPythonInstance instance, CallExpression expr) { // Function may not have been walked yet. Do it now. SymbolTable.Evaluate(p.FunctionDefinition); - return instance.Call(p.Name, ArgumentSet.Empty); + return instance.Call(p.Name, ArgumentSet.Empty(expr, this)); } diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Generics.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Generics.cs index e9ff23df2..f815271f7 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Generics.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Generics.cs @@ -88,7 +88,7 @@ private IMember CreateSpecificTypeFromIndex(IGenericType gt, IReadOnlyList 0) { - return gt.CreateSpecificType(new ArgumentSet(indices)); + return gt.CreateSpecificType(new ArgumentSet(indices, expr, this)); } // TODO: report too few type arguments for the generic expression. return UnknownType; @@ -132,7 +132,7 @@ private IMember CreateClassInstance(PythonClassType cls, IReadOnlyList var argSet = initOverload != null ? new ArgumentSet(initFunc, 0, null, callExpr, this) - : new ArgumentSet(constructorArguments); + : new ArgumentSet(constructorArguments, callExpr, this); argSet.Evaluate(); var specificType = cls.CreateSpecificType(argSet); diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs index b9676e19b..d8f5c8a2f 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs @@ -47,7 +47,7 @@ private IMember GetValueFromUnaryOp(UnaryExpression expr, string op) { var fn = instance.GetPythonType()?.GetMember(op); // Process functions declared in code modules. Scraped/compiled/stub modules do not actually perform any operations. if (fn?.DeclaringModule != null && (fn.DeclaringModule.ModuleType == ModuleType.User || fn.DeclaringModule.ModuleType == ModuleType.Library)) { - var result = fn.Call(instance, op, ArgumentSet.Empty); + var result = fn.Call(instance, op, ArgumentSet.Empty(expr, this)); if (!result.IsUnknown()) { return result; } @@ -132,9 +132,9 @@ private IMember GetValueFromBinaryOp(Expression expr) { if (op.IsComparison()) { // If the op is a comparison, and the thing on the left is the builtin, // flip the operation and call it instead. - ret = CallOperator(op.InvertComparison(), right, rightType, left, leftType, tryRight: false); + ret = CallOperator(op.InvertComparison(), right, rightType, left, leftType, expr, tryRight: false); } else { - ret = CallOperator(op, left, leftType, right, rightType, tryLeft: false); + ret = CallOperator(op, left, leftType, right, rightType, expr, tryLeft: false); } if (!ret.IsUnknown()) { @@ -146,7 +146,7 @@ private IMember GetValueFromBinaryOp(Expression expr) { if (rightIsSupported) { // Try calling the function on the left side, otherwise just return right. - var ret = CallOperator(op, left, leftType, right, rightType, tryRight: false); + var ret = CallOperator(op, left, leftType, right, rightType, expr, tryRight: false); if (!ret.IsUnknown()) { return ret; @@ -155,13 +155,13 @@ private IMember GetValueFromBinaryOp(Expression expr) { return op.IsComparison() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : right; } - var callRet = CallOperator(op, left, leftType, right, rightType); + var callRet = CallOperator(op, left, leftType, right, rightType, expr); if (!callRet.IsUnknown()) { return callRet; } if (op.IsComparison()) { - callRet = CallOperator(op.InvertComparison(), right, rightType, left, leftType); + callRet = CallOperator(op.InvertComparison(), right, rightType, left, leftType, expr); if (!callRet.IsUnknown()) { return callRet; @@ -197,18 +197,18 @@ private IMember GetValueFromBinaryOp(Expression expr) { return left.IsUnknown() ? right : left; } - private IMember CallOperator(PythonOperator op, IMember left, IPythonType leftType, IMember right, IPythonType rightType, bool tryLeft = true, bool tryRight = true) { + private IMember CallOperator(PythonOperator op, IMember left, IPythonType leftType, IMember right, IPythonType rightType, Expression expr, bool tryLeft = true, bool tryRight = true) { var (funcName, swappedFuncName) = OpMethodName(op); if (tryLeft && funcName != null && left is IPythonInstance lpi) { - var ret = leftType.Call(lpi, funcName, new ArgumentSet(new[] { right })); + var ret = leftType.Call(lpi, funcName, new ArgumentSet(new[] { right }, expr, this)); if (!ret.IsUnknown()) { return ret; } } if (tryRight && swappedFuncName != null && right is IPythonInstance rpi) { - var ret = rightType.Call(rpi, swappedFuncName, new ArgumentSet(new[] { left })); + var ret = rightType.Call(rpi, swappedFuncName, new ArgumentSet(new[] { left }, expr, this)); if (!ret.IsUnknown()) { return ret; } diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs index 392dc1abe..55aa4296e 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs @@ -271,7 +271,7 @@ private IMember GetValueFromMember(MemberExpression expr) { case IPythonClassType _: return value; case IPythonPropertyType prop: - return prop.Call(instance, prop.Name, ArgumentSet.Empty); + return prop.Call(instance, prop.Name, ArgumentSet.Empty(expr, this)); case IPythonType p: return new PythonBoundType(p, instance); case null: diff --git a/src/Analysis/Ast/Impl/Analyzer/Handlers/AssignmentHandler.cs b/src/Analysis/Ast/Impl/Analyzer/Handlers/AssignmentHandler.cs index 1626e8c5d..5837a9d0c 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Handlers/AssignmentHandler.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Handlers/AssignmentHandler.cs @@ -116,7 +116,7 @@ private void HandleTypedVariable(IPythonType variableType, IMember value, Expres instance = value; } } - instance = instance ?? variableType?.CreateInstance(variableType.Name, ArgumentSet.Empty) ?? Eval.UnknownType; + instance = instance ?? variableType?.CreateInstance(variableType.Name, ArgumentSet.Empty(expr, Eval)) ?? Eval.UnknownType; if (expr is NameExpression ne) { Eval.DeclareVariable(ne.Name, instance, VariableSource.Declaration, ne); diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs index 847bbc000..02ebc4928 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs @@ -35,7 +35,6 @@ internal sealed class FunctionEvaluator : MemberEvaluator { public FunctionEvaluator(ExpressionEval eval, PythonFunctionOverload overload) : base(eval, overload.FunctionDefinition) { - _overload = overload; _function = overload.ClassMember ?? throw new NullReferenceException(nameof(overload.ClassMember)); _self = _function.DeclaringType as PythonClassType; @@ -78,7 +77,7 @@ private IPythonType TryDetermineReturnValue() { if (!annotationType.IsUnknown()) { // Annotations are typically types while actually functions return // instances unless specifically annotated to a type such as Type[T]. - var t = annotationType.CreateInstance(annotationType.Name, ArgumentSet.Empty); + var t = annotationType.CreateInstance(annotationType.Name, ArgumentSet.WithoutContext); // If instance could not be created, such as when return type is List[T] and // type of T is not yet known, just use the type. var instance = t.IsUnknown() ? annotationType : t; diff --git a/src/Analysis/Ast/Impl/Specializations/Typing/TypingModule.cs b/src/Analysis/Ast/Impl/Specializations/Typing/TypingModule.cs index 8e280f25b..6fd4cb1e8 100644 --- a/src/Analysis/Ast/Impl/Specializations/Typing/TypingModule.cs +++ b/src/Analysis/Ast/Impl/Specializations/Typing/TypingModule.cs @@ -132,16 +132,7 @@ private void SpecializeMembers() { _members["Any"] = new AnyType(this); - // AnyStr - var str = Interpreter.GetBuiltinType(BuiltinTypeId.Str); - var bytes = Interpreter.GetBuiltinType(BuiltinTypeId.Bytes); - var unicode = Interpreter.GetBuiltinType(BuiltinTypeId.Unicode); - var anyStrName = new PythonConstant("AnyStr", str); - - var anyStrArgs = Interpreter.LanguageVersion.Is3x() - ? new IMember[] { anyStrName, str, bytes } - : new IMember[] { anyStrName, str, unicode }; - _members["AnyStr"] = GenericTypeParameter.FromTypeVar(new ArgumentSet(anyStrArgs), this); + _members["AnyStr"] = CreateAnyStr(); _members["Optional"] = new GenericType("Optional", CreateOptional, this); _members["Type"] = new GenericType("Type", CreateType, this); @@ -310,6 +301,21 @@ private IPythonType CreateType(IReadOnlyList typeArgs) { return Interpreter.UnknownType; } + private IPythonType CreateAnyStr() { + var str = Interpreter.GetBuiltinType(BuiltinTypeId.Str); + var bytes = Interpreter.GetBuiltinType(BuiltinTypeId.Bytes); + var unicode = Interpreter.GetBuiltinType(BuiltinTypeId.Unicode); + var name = "AnyStr"; + + var constraints = Interpreter.LanguageVersion.Is3x() + ? new IPythonType[] { str, bytes } + : new IPythonType[] { str, unicode }; + var docArgs = new[] { $"'{name}'" }.Concat(constraints.Select(c => c.Name)); + var documentation = CodeFormatter.FormatSequence("TypeVar", '(', docArgs); + + return new GenericTypeParameter(name, this, constraints, documentation, default); + } + private IPythonType CreateGenericClassParameter(IReadOnlyList typeArgs) { // Handle Generic[_T1, _T2, ...]. _T1, et al are IGenericTypeParameter from TypeVar. // Hold the parameter until concrete type is provided at the time of the class instantiation. diff --git a/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingIterator.cs b/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingIterator.cs index 16d172527..124c7c862 100644 --- a/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingIterator.cs +++ b/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingIterator.cs @@ -39,7 +39,7 @@ public override IMember Next { } else if (_index < _iteratorType.ItemTypes.Count) { itemType = _iteratorType.ItemTypes[_index++]; } - return itemType?.CreateInstance(itemType.Name, ArgumentSet.Empty) ?? UnknownType; + return itemType?.CreateInstance(itemType.Name, ArgumentSet.WithoutContext) ?? UnknownType; } } } diff --git a/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingTuple.cs b/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingTuple.cs index 93c9b52a2..52960406d 100644 --- a/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingTuple.cs +++ b/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingTuple.cs @@ -33,6 +33,6 @@ public override IPythonIterator GetIterator() { } public override IMember Index(object index) - => _collectionType.Index(this, index).GetPythonType().CreateInstance(null, ArgumentSet.Empty); + => _collectionType.Index(this, index).GetPythonType().CreateInstance(null, ArgumentSet.WithoutContext); } } diff --git a/src/Analysis/Ast/Impl/Types/ArgumentSet.cs b/src/Analysis/Ast/Impl/Types/ArgumentSet.cs index 6aa2b5038..1cac04fba 100644 --- a/src/Analysis/Ast/Impl/Types/ArgumentSet.cs +++ b/src/Analysis/Ast/Impl/Types/ArgumentSet.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using Microsoft.Python.Analysis.Analyzer; using Microsoft.Python.Analysis.Analyzer.Evaluation; using Microsoft.Python.Analysis.Diagnostics; @@ -38,7 +39,7 @@ internal sealed class ArgumentSet : IArgumentSet { private readonly DictArg _dictArgument; private bool _evaluated; - public static IArgumentSet Empty = new ArgumentSet(); + public static IArgumentSet WithoutContext = new ArgumentSet(); /// Module that declares the function public IPythonModule DeclaringModule { get; } @@ -49,19 +50,38 @@ internal sealed class ArgumentSet : IArgumentSet { public int OverloadIndex { get; } public IExpressionEvaluator Eval { get; } + public Expression Expression { get; } private ArgumentSet() { } - public ArgumentSet(IReadOnlyList typeArgs) { - _arguments = typeArgs.Select(t => new Argument(t)).ToList(); - _evaluated = true; + /// + /// Creates an empty argument set with some context in how the argument set was used. + /// + /// Expression associated with argument set. + /// Evaluator for the expression involving the argument set. + /// + public static ArgumentSet Empty(Expression expr, IExpressionEvaluator eval) { + return new ArgumentSet(new List(), expr, eval); } + + /// + /// Creates a set of arguments for a call + /// + /// Use in the cases a corresponding function is unknown, but it is still convenient to have the context + /// of the expression which the arguments are needed for and the evaluator that is analyzing + /// that expression. + /// + /// + /// Arguments for the call. + /// Expression for the call. + /// Evaluator of the current analysis. + public ArgumentSet(IReadOnlyList args, Expression expr, IExpressionEvaluator eval) { + _arguments = args.Select(t => new Argument(t)).ToList(); + Expression = expr; + Eval = eval; - public ArgumentSet(IReadOnlyList memberArgs) { - _arguments = memberArgs.Select(t => new Argument(t)).ToList(); _evaluated = true; } - public ArgumentSet(IPythonFunctionType fn, int overloadIndex, IPythonInstance instance, CallExpression callExpr, ExpressionEval eval) : this(fn, overloadIndex, instance, callExpr, eval.Module, eval) { } @@ -81,6 +101,7 @@ public ArgumentSet(IPythonFunctionType fn, int overloadIndex, IPythonInstance in Eval = eval; OverloadIndex = overloadIndex; DeclaringModule = fn.DeclaringModule; + Expression = callExpr; if (callExpr == null) { // Typically invoked by specialization code without call expression in the code. diff --git a/src/Analysis/Ast/Impl/Types/Definitions/IArgumentSet.cs b/src/Analysis/Ast/Impl/Types/Definitions/IArgumentSet.cs index bc1caa61b..4387b9efa 100644 --- a/src/Analysis/Ast/Impl/Types/Definitions/IArgumentSet.cs +++ b/src/Analysis/Ast/Impl/Types/Definitions/IArgumentSet.cs @@ -138,8 +138,13 @@ public interface IArgumentSet { int OverloadIndex { get; } /// - /// Evaluator associated with the set. + /// Evaluator associated with the argument set. /// IExpressionEvaluator Eval { get; } + + /// + /// Expression associated with the argument set + /// + Expression Expression { get; } } } diff --git a/src/Analysis/Ast/Impl/Types/PythonClassType.cs b/src/Analysis/Ast/Impl/Types/PythonClassType.cs index 850cf4893..ff6375b0f 100644 --- a/src/Analysis/Ast/Impl/Types/PythonClassType.cs +++ b/src/Analysis/Ast/Impl/Types/PythonClassType.cs @@ -402,7 +402,7 @@ public IPythonType CreateSpecificType(IArgumentSet args) { .Where(p => !p.IsUnknown()) .ToArray(); if (st.Length > 0) { - var type = gt.CreateSpecificType(new ArgumentSet(st)); + var type = gt.CreateSpecificType(new ArgumentSet(st, args.Expression, args.Eval)); if (!type.IsUnknown()) { bases.Add(type); } diff --git a/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs b/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs index 0e5f90a51..77187a780 100644 --- a/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs +++ b/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs @@ -167,7 +167,7 @@ private IMember CreateSpecificReturnFromClassType(IPythonClassType selfClassType } if (typeArgs != null) { - var specificReturnValue = returnClassType.CreateSpecificType(new ArgumentSet(typeArgs)); + var specificReturnValue = returnClassType.CreateSpecificType(new ArgumentSet(typeArgs, args?.Expression, args?.Eval)); return new PythonInstance(specificReturnValue); } diff --git a/src/Analysis/Ast/Impl/Types/PythonPropertyType.cs b/src/Analysis/Ast/Impl/Types/PythonPropertyType.cs index f10078945..9728627fa 100644 --- a/src/Analysis/Ast/Impl/Types/PythonPropertyType.cs +++ b/src/Analysis/Ast/Impl/Types/PythonPropertyType.cs @@ -44,10 +44,10 @@ public PythonPropertyType(string name, Location location, IPythonType declaringT public string Description => Type == null ? Resources.PropertyOfUnknownType : Resources.PropertyOfType.FormatUI(Type.Name); public override IMember Call(IPythonInstance instance, string memberName, IArgumentSet args) - => _getter.Call(args, instance?.GetPythonType() ?? DeclaringType); + => _getter?.Call(args, instance?.GetPythonType() ?? DeclaringType); #endregion internal void AddOverload(IPythonFunctionOverload overload) => _getter = _getter ?? overload; - private IPythonType Type => _getter?.Call(ArgumentSet.Empty, DeclaringType)?.GetPythonType(); + private IPythonType Type => _getter?.Call(ArgumentSet.WithoutContext, DeclaringType)?.GetPythonType(); } } diff --git a/src/Analysis/Ast/Impl/Values/Collections/PythonDictionary.cs b/src/Analysis/Ast/Impl/Values/Collections/PythonDictionary.cs index 53d9fef35..d60b76bff 100644 --- a/src/Analysis/Ast/Impl/Values/Collections/PythonDictionary.cs +++ b/src/Analysis/Ast/Impl/Values/Collections/PythonDictionary.cs @@ -62,7 +62,7 @@ public IReadOnlyList Items _contents.TryGetValue(key, out var value) ? value : UnknownType; public override IPythonIterator GetIterator() => - Call(@"iterkeys", ArgumentSet.Empty) as IPythonIterator ?? new EmptyIterator(Type.DeclaringModule.Interpreter.UnknownType); + Call(@"iterkeys", ArgumentSet.WithoutContext) as IPythonIterator ?? new EmptyIterator(Type.DeclaringModule.Interpreter.UnknownType); public override IMember Index(object key) => key is IMember m ? this[m] : UnknownType; diff --git a/src/Analysis/Ast/Impl/Values/Collections/PythonInstanceIterator.cs b/src/Analysis/Ast/Impl/Values/Collections/PythonInstanceIterator.cs index 9dbdafffe..3db7ee4e0 100644 --- a/src/Analysis/Ast/Impl/Values/Collections/PythonInstanceIterator.cs +++ b/src/Analysis/Ast/Impl/Values/Collections/PythonInstanceIterator.cs @@ -29,7 +29,7 @@ public PythonInstanceIterator(IMember instance, IPythonInterpreter interpreter) __next__ = instance.GetPythonType().GetMember(@"__next__") as IPythonFunctionType; } - public IMember Next => __next__?.Call(null, @"__next__", ArgumentSet.Empty) ?? UnknownType; + public IMember Next => __next__?.Call(null, @"__next__", ArgumentSet.WithoutContext) ?? UnknownType; public override IMember Call(string memberName, IArgumentSet args) { // Specializations diff --git a/src/Analysis/Ast/Impl/Values/PythonInstance.cs b/src/Analysis/Ast/Impl/Values/PythonInstance.cs index 2aed9f4cb..0da044063 100644 --- a/src/Analysis/Ast/Impl/Values/PythonInstance.cs +++ b/src/Analysis/Ast/Impl/Values/PythonInstance.cs @@ -56,7 +56,7 @@ public virtual IMember Call(string memberName, IArgumentSet args) { public virtual IPythonIterator GetIterator() { var iteratorFunc = Type.GetMember(@"__iter__") as IPythonFunctionType; var o = iteratorFunc?.Overloads.FirstOrDefault(); - var instance = o?.Call(ArgumentSet.Empty, Type); + var instance = o?.Call(ArgumentSet.WithoutContext, Type); if (instance != null) { return new PythonInstanceIterator(instance, Type.DeclaringModule.Interpreter); } diff --git a/src/Analysis/Ast/Test/FluentAssertions/PythonFunctionOverloadAssertions.cs b/src/Analysis/Ast/Test/FluentAssertions/PythonFunctionOverloadAssertions.cs index 2744f69b3..6ab5b0f8e 100644 --- a/src/Analysis/Ast/Test/FluentAssertions/PythonFunctionOverloadAssertions.cs +++ b/src/Analysis/Ast/Test/FluentAssertions/PythonFunctionOverloadAssertions.cs @@ -31,7 +31,7 @@ public PythonFunctionOverloadAssertions(IPythonFunctionOverload pythonFunctionOv protected override string Identifier => nameof(IPythonFunctionOverload); public AndWhichConstraint HaveReturnType(string because = "", params object[] reasonArgs) { - var returnType = Subject.Call(ArgumentSet.Empty, null); + var returnType = Subject.Call(ArgumentSet.WithoutContext, null); Execute.Assertion.ForCondition(returnType != null) .BecauseOf(because, reasonArgs) .FailWith($"Expected {Subject.Name} overload to have a return type{{reason}}, but it has none."); @@ -40,7 +40,7 @@ public AndWhichConstraint HaveRet } public AndWhichConstraint HaveReturnType(BuiltinTypeId typeid, string because = "", params object[] reasonArgs) { - Subject.Call(ArgumentSet.Empty, null).GetPythonType().TypeId.Should().Be(typeid); + Subject.Call(ArgumentSet.WithoutContext, null).GetPythonType().TypeId.Should().Be(typeid); return new AndWhichConstraint(this, Subject); } @@ -106,7 +106,7 @@ public AndConstraint HaveNoParameters(string b => HaveParameters(Enumerable.Empty(), because, reasonArgs); public AndConstraint HaveReturnType(string type, string because = "", params object[] reasonArgs) { - var returnType = Subject.Call(ArgumentSet.Empty, null).GetPythonType(); + var returnType = Subject.Call(ArgumentSet.WithoutContext, null).GetPythonType(); Execute.Assertion.ForCondition(string.Equals(returnType.Name, type, StringComparison.Ordinal)) .BecauseOf(because, reasonArgs) .FailWith($"Expected {Subject.Name} to have return type [{type}]{{reason}}, but it has [{returnType}].");