public FunctionAnalysisUnit(FunctionAnalysisUnit originalUnit, CallChain callChain, ArgumentSet callArgs) : base(originalUnit.Ast, null) { _originalUnit = originalUnit; _declUnit = originalUnit._declUnit; Function = originalUnit.Function; CallChain = callChain; var scope = new FunctionScope( Function, Ast, originalUnit.Scope.OuterScope, originalUnit.DeclaringModule.ProjectEntry ); scope.UpdateParameters(this, callArgs, false, originalUnit.Scope as FunctionScope); _scope = scope; var walker = new OverviewWalker(_originalUnit.ProjectEntry, this, Tree); if (Ast.Body != null) { Ast.Body.Walk(walker); } AnalysisLog.NewUnit(this); Enqueue(); }
internal bool UpdateParameters(FunctionAnalysisUnit unit, ArgumentSet others, bool enqueue = true, FunctionScope scopeWithDefaultParameters = null) { EnsureParameters(unit); var astParams = Function.FunctionDefinition.Parameters; bool added = false; var entry = unit.ProjectEntry; var state = unit.ProjectState; var limits = state.Limits; for (int i = 0; i < others.Args.Length && i < astParams.Count; ++i) { VariableDef param; if (!TryGetVariable(astParams[i].Name, out param)) { Debug.Assert(false, "Parameter " + astParams[i].Name + " has no variable in this scope"); param = AddVariable(astParams[i].Name); } param.MakeUnionStrongerIfMoreThan(limits.NormalArgumentTypes, others.Args[i]); added |= param.AddTypes(entry, others.Args[i], false); } if (_seqParameters != null) { _seqParameters.List.MakeUnionStrongerIfMoreThan(limits.ListArgumentTypes, others.SequenceArgs); added |= _seqParameters.List.AddTypes(unit, new[] { others.SequenceArgs }); } if (_dictParameters != null) { _dictParameters.Dict.MakeUnionStrongerIfMoreThan(limits.DictArgumentTypes, others.DictArgs); added |= _dictParameters.Dict.AddTypes(Function.FunctionDefinition, unit, state.GetConstant(""), others.DictArgs); } if (scopeWithDefaultParameters != null) { for (int i = 0; i < others.Args.Length && i < astParams.Count; ++i) { VariableDef defParam, param; if (TryGetVariable(astParams[i].Name, out param) && !param.TypesNoCopy.Any() && scopeWithDefaultParameters.TryGetVariable(astParams[i].Name, out defParam)) { param.MakeUnionStrongerIfMoreThan(limits.NormalArgumentTypes, defParam.TypesNoCopy); added |= param.AddTypes(entry, defParam.TypesNoCopy, false); } } } if (enqueue && added) { unit.Enqueue(); } return added; }
private IAnalysisSet DoCall(Node node, AnalysisUnit callingUnit, FunctionAnalysisUnit calledUnit, ArgumentSet callArgs) { calledUnit.UpdateParameters(callArgs); calledUnit.ReturnValue.AddDependency(callingUnit); return(calledUnit.ReturnValue.Types); }
public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { var callArgs = ArgumentSet.FromArgs(FunctionDefinition, unit, args, keywordArgNames); if (keywordArgNames != null && keywordArgNames.Any()) { _analysisUnit.AddNamedParameterReferences(unit, keywordArgNames); } var res = DoCall(node, unit, _analysisUnit, callArgs); if (_derived != null) { foreach (FunctionInfo derived in _derived) { var derivedResult = derived.DoCall(node, unit, derived._analysisUnit, callArgs); res = res.Union(derivedResult); } } if (_analysisUnit.State.Limits.PropagateParameterTypeToBaseMethods && _analysisUnit.Scope.OuterScope is ClassScope parentClass) { var baseMethods = DDG.LookupBaseMethods(Name, parentClass.Class.Mro, AnalysisUnit.Ast, AnalysisUnit); foreach (FunctionInfo baseMethod in baseMethods.OfType <FunctionInfo>()) { baseMethod.DoCall(node, unit, baseMethod._analysisUnit, callArgs); } } if (_callsWithClosure != null) { var chain = new CallChain(node, unit, _callDepthLimit); var aggregate = GetAggregate(unit); if (!_callsWithClosure.TryGetValue(aggregate, chain, _callDepthLimit, out var calledUnit) && !unit.ForEval) { _callsSinceLimitChange += 1; if (_callsSinceLimitChange >= ProjectState.Limits.DecreaseCallDepth && _callDepthLimit > 1) { _callDepthLimit -= 1; _callsSinceLimitChange = 0; AnalysisLog.ReduceCallDepth(this, _callsWithClosure.Count, _callDepthLimit); _callsWithClosure.Clear(); chain = chain.Trim(_callDepthLimit); } calledUnit = new FunctionClosureAnalysisUnit(aggregate, (FunctionAnalysisUnit)AnalysisUnit, chain); _callsWithClosure.Add(aggregate, chain, calledUnit); calledUnit.Enqueue(); } Debug.Assert(calledUnit != null || unit.ForEval); res.Split(v => v.IsResolvable(), out _, out var nonLazy); res = DoCall(node, unit, calledUnit, callArgs); res = res.Union(nonLazy); } var context = unit.ForEval ? ResolutionContext.Complete : new ResolutionContext { Caller = this, CallArgs = callArgs, CallSite = node }; var r = res.Resolve(unit, context, out _); return(r); }
internal bool UpdateParameters(ArgumentSet callArgs, bool enqueue = true) { var defScope = _originalUnit != null ? _originalUnit.Scope as FunctionScope : null; return ((FunctionScope)Scope).UpdateParameters(this, callArgs, enqueue, defScope); }
internal override bool UpdateParameters(ArgumentSet callArgs, bool enqueue = true) { var defScope = _originalUnit.Scope; return ((FunctionScope)Scope).UpdateParameters(this, callArgs, enqueue, (FunctionScope)defScope); }
internal virtual bool UpdateParameters(ArgumentSet callArgs, bool enqueue = true) { return ((FunctionScope)Scope).UpdateParameters(this, callArgs, enqueue, null); }
public static bool AreCompatible(ArgumentSet x, ArgumentSet y) { return(x.Args.Length == y.Args.Length); }
public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { var callArgs = ArgumentSet.FromArgs(FunctionDefinition, unit, args, keywordArgNames); FunctionAnalysisUnit calledUnit; bool updateArguments = true; if (callArgs.Count == 0 || (ProjectState.Limits.UnifyCallsToNew && Name == "__new__") || _callDepthLimit == 0) { calledUnit = (FunctionAnalysisUnit)AnalysisUnit; } else { if (_allCalls == null) { _allCalls = new CallChainSet <FunctionAnalysisUnit>(); } var chain = new CallChain(node, unit, _callDepthLimit); if (!_allCalls.TryGetValue(unit.ProjectEntry, chain, _callDepthLimit, out calledUnit)) { if (unit.ForEval) { // Call expressions that weren't analyzed get the union result // of all calls to this function. var res = AnalysisSet.Empty; foreach (var call in _allCalls.Values) { res = res.Union(call.ReturnValue.TypesNoCopy); } return(res); } else { _callsSinceLimitChange += 1; if (_callsSinceLimitChange >= ProjectState.Limits.DecreaseCallDepth && _callDepthLimit > 1) { _callDepthLimit -= 1; _callsSinceLimitChange = 0; AnalysisLog.ReduceCallDepth(this, _allCalls.Count, _callDepthLimit); _allCalls.Clear(); chain = chain.Trim(_callDepthLimit); } calledUnit = new FunctionAnalysisUnit((FunctionAnalysisUnit)AnalysisUnit, chain, callArgs); _allCalls.Add(unit.ProjectEntry, chain, calledUnit); updateArguments = false; } } } if (updateArguments && calledUnit.UpdateParameters(callArgs)) { AnalysisLog.UpdateUnit(calledUnit); } if (keywordArgNames != null && keywordArgNames.Any()) { calledUnit.AddNamedParameterReferences(unit, keywordArgNames); } calledUnit.ReturnValue.AddDependency(unit); return(calledUnit.ReturnValue.Types); }
public static ArgumentSet FromArgs(FunctionDefinition node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgs) { // TODO: Warn when a keyword argument is provided and it maps to // something which is also a positional argument: // def f(a, b, c): // print a, b, c // // f(2, 3, a=42) int kwArgsOffset = args.Length - keywordArgs.Length; var seqArgs = AnalysisSet.EmptyUnion; var dictArgs = AnalysisSet.EmptyUnion; int listArgsIndex = -1; int dictArgsIndex = -1; int argCount = node.Parameters.Length; var newArgs = new IAnalysisSet[argCount]; for (int i = 0; i < node.Parameters.Length; ++i) { if (node.Parameters[i].Kind == ParameterKind.List) { listArgsIndex = i; } else if (node.Parameters[i].Kind == ParameterKind.Dictionary) { dictArgsIndex = i; } newArgs[i] = AnalysisSet.Empty; } int lastPositionFilled = -1; for (int i = 0; i < kwArgsOffset; ++i) { if (i < argCount && (listArgsIndex < 0 || i < listArgsIndex)) { newArgs[i] = newArgs[i].Union(args[i]); lastPositionFilled = i; } else if (listArgsIndex >= 0) { foreach (var ns in args[i]) { var sseq = ns as StarArgsSequenceInfo; if (sseq != null && i < node.Parameters.Length && sseq._node == node.Parameters[i]) { seqArgs = seqArgs.Add(unit.State.ClassInfos[BuiltinTypeId.Tuple].Instance); } else { seqArgs = seqArgs.Add(ns); } } } else { // TODO: Warn about extra parameters } } for (int i = kwArgsOffset; i < args.Length; ++i) { if (i - kwArgsOffset >= keywordArgs.Length || keywordArgs[i - kwArgsOffset] == null) { continue; } var name = keywordArgs[i - kwArgsOffset].Name; if (name.Equals("*", StringComparison.Ordinal)) { foreach (var ns in args[i]) { SequenceInfo seq; StarArgsSequenceInfo sseq; if ((sseq = ns as StarArgsSequenceInfo) != null) { seqArgs = seqArgs.Union(sseq.IndexTypes.SelectMany(def => def.Types)); } else if ((seq = ns as SequenceInfo) != null) { for (int j = 0; j < seq.IndexTypes.Length; ++j) { int k = lastPositionFilled + j + 1; if (k < node.Parameters.Length && node.Parameters[k].Kind == ParameterKind.Normal) { newArgs[k] = newArgs[k].Union(seq.IndexTypes[j].Types); } else if (listArgsIndex >= 0) { seqArgs = seqArgs.Union(seq.IndexTypes[j].Types); } else { // TODO: Warn about extra parameters } } } else if (listArgsIndex >= 0) { newArgs[listArgsIndex] = newArgs[listArgsIndex].Add(ns); } } } else if (name.Equals("**", StringComparison.Ordinal)) { foreach (var dict in args[i].OfType <DictionaryInfo>()) { foreach (var kv in dict._keysAndValues.KeyValueTypes) { var paramName = kv.Key.GetConstantValueAsString(); if (string.IsNullOrEmpty(paramName)) { continue; } for (int j = 0; j < argCount; ++j) { if (node.Parameters[j].Name.Equals(paramName, StringComparison.Ordinal)) { newArgs[j] = newArgs[j].Union(kv.Value); break; } } } } if (dictArgsIndex >= 0) { foreach (var ns in args[i]) { var sdict = ns as StarArgsDictionaryInfo; if (sdict != null) { dictArgs = dictArgs.Union(sdict._keysAndValues.AllValueTypes); } else { newArgs[dictArgsIndex] = newArgs[dictArgsIndex].Add(ns); } } } } else { bool foundParam = false; for (int j = 0; j < argCount; ++j) { if (node.Parameters[j].Name.Equals(name, StringComparison.Ordinal)) { newArgs[j] = newArgs[j].Union(args[i]); foundParam = true; break; } } if (!foundParam && dictArgsIndex >= 0) { dictArgs = dictArgs.Union(args[i]); } } } var limits = unit.State.Limits; for (int i = 0; i < argCount; ++i) { newArgs[i] = ReduceArgs(newArgs[i], limits.NormalArgumentTypes); } var set = new ArgumentSet( newArgs, ReduceArgs(seqArgs, limits.ListArgumentTypes), ReduceArgs(dictArgs, limits.DictArgumentTypes), null ); return(set); }
public static bool AreCompatible(ArgumentSet x, ArgumentSet y) { return x.Args.Length == y.Args.Length; }