luau/Analysis/src/AnyTypeSummary.cpp

883 lines
26 KiB
C++
Raw Normal View History

2024-07-26 01:10:42 +01:00
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AnyTypeSummary.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Clone.h"
#include "Luau/Common.h"
#include "Luau/Config.h"
#include "Luau/ConstraintGenerator.h"
#include "Luau/ConstraintSolver.h"
#include "Luau/DataFlowGraph.h"
#include "Luau/DcrLogger.h"
#include "Luau/Module.h"
#include "Luau/Parser.h"
#include "Luau/Scope.h"
#include "Luau/StringUtils.h"
#include "Luau/TimeTrace.h"
#include "Luau/ToString.h"
#include "Luau/Transpiler.h"
#include "Luau/TypeArena.h"
#include "Luau/TypeChecker2.h"
#include "Luau/NonStrictTypeChecker.h"
#include "Luau/TypeInfer.h"
#include "Luau/Variant.h"
#include "Luau/VisitType.h"
#include "Luau/TypePack.h"
#include "Luau/TypeOrPack.h"
#include <algorithm>
#include <memory>
#include <chrono>
#include <condition_variable>
#include <exception>
#include <mutex>
#include <stdexcept>
#include <string>
#include <iostream>
#include <stdio.h>
LUAU_FASTFLAGVARIABLE(StudioReportLuauAny, false);
LUAU_FASTINTVARIABLE(LuauAnySummaryRecursionLimit, 300);
LUAU_FASTFLAG(DebugLuauMagicTypes);
namespace Luau
{
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::traverse(const Module* module, AstStat* src, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
visit(findInnerMostScope(src->location, module), src, module, builtinTypes);
2024-07-26 01:10:42 +01:00
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStat* stat, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
RecursionLimiter limiter{&recursionCount, FInt::LuauAnySummaryRecursionLimit};
if (auto s = stat->as<AstStatBlock>())
return visit(scope, s, module, builtinTypes);
else if (auto i = stat->as<AstStatIf>())
return visit(scope, i, module, builtinTypes);
else if (auto s = stat->as<AstStatWhile>())
return visit(scope, s, module, builtinTypes);
else if (auto s = stat->as<AstStatRepeat>())
return visit(scope, s, module, builtinTypes);
else if (auto r = stat->as<AstStatReturn>())
return visit(scope, r, module, builtinTypes);
else if (auto e = stat->as<AstStatExpr>())
return visit(scope, e, module, builtinTypes);
else if (auto s = stat->as<AstStatLocal>())
return visit(scope, s, module, builtinTypes);
else if (auto s = stat->as<AstStatFor>())
return visit(scope, s, module, builtinTypes);
else if (auto s = stat->as<AstStatForIn>())
return visit(scope, s, module, builtinTypes);
else if (auto a = stat->as<AstStatAssign>())
return visit(scope, a, module, builtinTypes);
else if (auto a = stat->as<AstStatCompoundAssign>())
return visit(scope, a, module, builtinTypes);
else if (auto f = stat->as<AstStatFunction>())
return visit(scope, f, module, builtinTypes);
else if (auto f = stat->as<AstStatLocalFunction>())
return visit(scope, f, module, builtinTypes);
else if (auto a = stat->as<AstStatTypeAlias>())
return visit(scope, a, module, builtinTypes);
else if (auto s = stat->as<AstStatDeclareGlobal>())
return visit(scope, s, module, builtinTypes);
else if (auto s = stat->as<AstStatDeclareFunction>())
return visit(scope, s, module, builtinTypes);
else if (auto s = stat->as<AstStatDeclareClass>())
return visit(scope, s, module, builtinTypes);
else if (auto s = stat->as<AstStatError>())
return visit(scope, s, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatBlock* block, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
RecursionCounter counter{&recursionCount};
if (recursionCount >= FInt::LuauAnySummaryRecursionLimit)
return; // don't report
for (AstStat* stat : block->body)
visit(scope, stat, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatIf* ifStatement, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
if (ifStatement->thenbody)
{
2024-08-02 00:25:12 +01:00
const Scope* thenScope = findInnerMostScope(ifStatement->thenbody->location, module);
2024-07-26 01:10:42 +01:00
visit(thenScope, ifStatement->thenbody, module, builtinTypes);
}
if (ifStatement->elsebody)
{
2024-08-02 00:25:12 +01:00
const Scope* elseScope = findInnerMostScope(ifStatement->elsebody->location, module);
2024-07-26 01:10:42 +01:00
visit(elseScope, ifStatement->elsebody, module, builtinTypes);
}
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatWhile* while_, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
const Scope* whileScope = findInnerMostScope(while_->location, module);
2024-07-26 01:10:42 +01:00
visit(whileScope, while_->body, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatRepeat* repeat, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
const Scope* repeatScope = findInnerMostScope(repeat->location, module);
2024-07-26 01:10:42 +01:00
visit(repeatScope, repeat->body, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatReturn* ret, const Module* module, NotNull<BuiltinTypes> builtinTypes)
{
const Scope* retScope = findInnerMostScope(ret->location, module);
auto ctxNode = getNode(rootSrc, ret);
2024-07-26 01:10:42 +01:00
for (auto val : ret->list)
{
if (isAnyCall(retScope, val, module, builtinTypes))
{
TelemetryTypePair types;
types.inferredType = toString(lookupType(val, module, builtinTypes));
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::FuncApp, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
if (isAnyCast(retScope, val, module, builtinTypes))
{
if (auto cast = val->as<AstExprTypeAssertion>())
{
TelemetryTypePair types;
types.annotatedType = toString(lookupAnnotation(cast->annotation, module, builtinTypes));
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(cast->expr, module, builtinTypes));
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Casts, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
}
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatLocal* local, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
auto ctxNode = getNode(rootSrc, local);
2024-07-26 01:10:42 +01:00
TypePackId values = reconstructTypePack(local->values, module, builtinTypes);
auto [head, tail] = flatten(values);
size_t posn = 0;
for (AstLocal* loc : local->vars)
{
if (local->vars.data[0] == loc && posn < local->values.size)
{
if (loc->annotation)
{
auto annot = lookupAnnotation(loc->annotation, module, builtinTypes);
if (containsAny(annot))
{
TelemetryTypePair types;
types.annotatedType = toString(annot);
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(local->values.data[posn], module, builtinTypes));
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::VarAnnot, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
2024-08-02 00:25:12 +01:00
const AstExprTypeAssertion* maybeRequire = local->values.data[posn]->as<AstExprTypeAssertion>();
if (!maybeRequire)
continue;
if (isAnyCast(scope, local->values.data[posn], module, builtinTypes))
{
TelemetryTypePair types;
types.inferredType = toString(head[std::min(local->values.size - 1, posn)]);
TypeInfo ti{Pattern::Casts, toString(ctxNode), types};
typeInfo.push_back(ti);
}
2024-07-26 01:10:42 +01:00
}
else
{
2024-08-02 00:25:12 +01:00
2024-07-26 01:10:42 +01:00
if (std::min(local->values.size - 1, posn) < head.size())
{
if (loc->annotation)
{
auto annot = lookupAnnotation(loc->annotation, module, builtinTypes);
if (containsAny(annot))
{
TelemetryTypePair types;
types.annotatedType = toString(annot);
types.inferredType = toString(head[std::min(local->values.size - 1, posn)]);
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::VarAnnot, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
}
else
{
if (tail)
{
if (containsAny(*tail))
{
TelemetryTypePair types;
types.inferredType = toString(*tail);
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::VarAny, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
}
}
++posn;
}
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatFor* for_, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
const Scope* forScope = findInnerMostScope(for_->location, module);
2024-07-26 01:10:42 +01:00
visit(forScope, for_->body, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatForIn* forIn, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
const Scope* loopScope = findInnerMostScope(forIn->location, module);
2024-07-26 01:10:42 +01:00
visit(loopScope, forIn->body, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatAssign* assign, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
auto ctxNode = getNode(rootSrc, assign);
2024-07-26 01:10:42 +01:00
TypePackId values = reconstructTypePack(assign->values, module, builtinTypes);
auto [head, tail] = flatten(values);
size_t posn = 0;
for (AstExpr* var : assign->vars)
{
TypeId tp = lookupType(var, module, builtinTypes);
if (containsAny(tp))
{
TelemetryTypePair types;
types.annotatedType = toString(tp);
auto loc = std::min(assign->vars.size - 1, posn);
if (head.size() >= assign->vars.size)
{
types.inferredType = toString(head[posn]);
}
else if (loc < head.size())
types.inferredType = toString(head[loc]);
else
types.inferredType = toString(builtinTypes->nilType);
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Assign, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
++posn;
}
for (AstExpr* val : assign->values)
{
if (isAnyCall(scope, val, module, builtinTypes))
{
TelemetryTypePair types;
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(val, module, builtinTypes));
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::FuncApp, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
if (isAnyCast(scope, val, module, builtinTypes))
{
if (auto cast = val->as<AstExprTypeAssertion>())
{
TelemetryTypePair types;
types.annotatedType = toString(lookupAnnotation(cast->annotation, module, builtinTypes));
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(val, module, builtinTypes));
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Casts, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
}
2024-08-02 00:25:12 +01:00
if (tail)
2024-07-26 01:10:42 +01:00
{
if (containsAny(*tail))
{
TelemetryTypePair types;
types.inferredType = toString(*tail);
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Assign, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatCompoundAssign* assign, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
auto ctxNode = getNode(rootSrc, assign);
2024-07-26 01:10:42 +01:00
TelemetryTypePair types;
types.inferredType = toString(lookupType(assign->value, module, builtinTypes));
types.annotatedType = toString(lookupType(assign->var, module, builtinTypes));
if (module->astTypes.contains(assign->var))
{
if (containsAny(*module->astTypes.find(assign->var)))
{
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Assign, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
else if (module->astTypePacks.contains(assign->var))
{
if (containsAny(*module->astTypePacks.find(assign->var)))
{
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Assign, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
if (isAnyCall(scope, assign->value, module, builtinTypes))
{
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::FuncApp, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
if (isAnyCast(scope, assign->value, module, builtinTypes))
{
if (auto cast = assign->value->as<AstExprTypeAssertion>())
{
types.annotatedType = toString(lookupAnnotation(cast->annotation, module, builtinTypes));
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(cast->expr, module, builtinTypes));
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Casts, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatFunction* function, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
TelemetryTypePair types;
types.inferredType = toString(lookupType(function->func, module, builtinTypes));
if (hasVariadicAnys(scope, function->func, module, builtinTypes))
{
TypeInfo ti{Pattern::VarAny, toString(function), types};
typeInfo.push_back(ti);
}
if (hasArgAnys(scope, function->func, module, builtinTypes))
{
TypeInfo ti{Pattern::FuncArg, toString(function), types};
typeInfo.push_back(ti);
}
if (hasAnyReturns(scope, function->func, module, builtinTypes))
{
TypeInfo ti{Pattern::FuncRet, toString(function), types};
typeInfo.push_back(ti);
}
if (function->func->body->body.size > 0)
visit(scope, function->func->body, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatLocalFunction* function, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
TelemetryTypePair types;
if (hasVariadicAnys(scope, function->func, module, builtinTypes))
{
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(function->func, module, builtinTypes));
2024-07-26 01:10:42 +01:00
TypeInfo ti{Pattern::VarAny, toString(function), types};
typeInfo.push_back(ti);
}
if (hasArgAnys(scope, function->func, module, builtinTypes))
{
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(function->func, module, builtinTypes));
2024-07-26 01:10:42 +01:00
TypeInfo ti{Pattern::FuncArg, toString(function), types};
typeInfo.push_back(ti);
}
if (hasAnyReturns(scope, function->func, module, builtinTypes))
{
2024-08-02 00:25:12 +01:00
types.inferredType = toString(lookupType(function->func, module, builtinTypes));
2024-07-26 01:10:42 +01:00
TypeInfo ti{Pattern::FuncRet, toString(function), types};
typeInfo.push_back(ti);
}
if (function->func->body->body.size > 0)
visit(scope, function->func->body, module, builtinTypes);
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatTypeAlias* alias, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
auto ctxNode = getNode(rootSrc, alias);
2024-07-26 01:10:42 +01:00
auto annot = lookupAnnotation(alias->type, module, builtinTypes);
if (containsAny(annot))
{
// no expr => no inference for aliases
TelemetryTypePair types;
types.annotatedType = toString(annot);
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::Alias, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatExpr* expr, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
auto ctxNode = getNode(rootSrc, expr);
2024-07-26 01:10:42 +01:00
if (isAnyCall(scope, expr->expr, module, builtinTypes))
{
TelemetryTypePair types;
types.inferredType = toString(lookupType(expr->expr, module, builtinTypes));
2024-08-02 00:25:12 +01:00
TypeInfo ti{Pattern::FuncApp, toString(ctxNode), types};
2024-07-26 01:10:42 +01:00
typeInfo.push_back(ti);
}
}
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatDeclareGlobal* declareGlobal, const Module* module, NotNull<BuiltinTypes> builtinTypes) {}
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatDeclareClass* declareClass, const Module* module, NotNull<BuiltinTypes> builtinTypes) {}
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatDeclareFunction* declareFunction, const Module* module, NotNull<BuiltinTypes> builtinTypes) {}
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
void AnyTypeSummary::visit(const Scope* scope, AstStatError* error, const Module* module, NotNull<BuiltinTypes> builtinTypes) {}
2024-07-26 01:10:42 +01:00
2024-08-02 00:25:12 +01:00
TypeId AnyTypeSummary::checkForFamilyInhabitance(const TypeId instance, const Location location)
2024-07-26 01:10:42 +01:00
{
if (seenTypeFamilyInstances.find(instance))
return instance;
seenTypeFamilyInstances.insert(instance);
return instance;
}
2024-08-02 00:25:12 +01:00
TypeId AnyTypeSummary::lookupType(const AstExpr* expr, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
const TypeId* ty = module->astTypes.find(expr);
2024-07-26 01:10:42 +01:00
if (ty)
return checkForFamilyInhabitance(follow(*ty), expr->location);
2024-08-02 00:25:12 +01:00
const TypePackId* tp = module->astTypePacks.find(expr);
2024-07-26 01:10:42 +01:00
if (tp)
{
if (auto fst = first(*tp, /*ignoreHiddenVariadics*/ false))
return checkForFamilyInhabitance(*fst, expr->location);
else if (finite(*tp) && size(*tp) == 0)
return checkForFamilyInhabitance(builtinTypes->nilType, expr->location);
}
return builtinTypes->errorRecoveryType();
}
2024-08-02 00:25:12 +01:00
TypePackId AnyTypeSummary::reconstructTypePack(AstArray<AstExpr*> exprs, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
if (exprs.size == 0)
return arena.addTypePack(TypePack{{}, std::nullopt});
std::vector<TypeId> head;
for (size_t i = 0; i < exprs.size - 1; ++i)
{
head.push_back(lookupType(exprs.data[i], module, builtinTypes));
}
2024-08-02 00:25:12 +01:00
const TypePackId* tail = module->astTypePacks.find(exprs.data[exprs.size - 1]);
2024-07-26 01:10:42 +01:00
if (tail)
return arena.addTypePack(TypePack{std::move(head), follow(*tail)});
else
return arena.addTypePack(TypePack{std::move(head), builtinTypes->errorRecoveryTypePack()});
}
2024-08-02 00:25:12 +01:00
bool AnyTypeSummary::isAnyCall(const Scope* scope, AstExpr* expr, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
if (auto call = expr->as<AstExprCall>())
{
TypePackId args = reconstructTypePack(call->args, module, builtinTypes);
if (containsAny(args))
return true;
TypeId func = lookupType(call->func, module, builtinTypes);
if (containsAny(func))
return true;
}
return false;
}
2024-08-02 00:25:12 +01:00
bool AnyTypeSummary::hasVariadicAnys(const Scope* scope, AstExprFunction* expr, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
if (expr->vararg && expr->varargAnnotation)
{
auto annot = lookupPackAnnotation(expr->varargAnnotation, module);
if (annot && containsAny(*annot))
{
return true;
}
}
return false;
}
2024-08-02 00:25:12 +01:00
bool AnyTypeSummary::hasArgAnys(const Scope* scope, AstExprFunction* expr, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
if (expr->args.size > 0)
{
for (const AstLocal* arg : expr->args)
{
if (arg->annotation)
{
auto annot = lookupAnnotation(arg->annotation, module, builtinTypes);
if (containsAny(annot))
{
return true;
}
}
}
}
return false;
}
2024-08-02 00:25:12 +01:00
bool AnyTypeSummary::hasAnyReturns(const Scope* scope, AstExprFunction* expr, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
if (!expr->returnAnnotation)
{
return false;
}
for (AstType* ret : expr->returnAnnotation->types)
{
if (containsAny(lookupAnnotation(ret, module, builtinTypes)))
{
return true;
}
}
if (expr->returnAnnotation->tailType)
{
auto annot = lookupPackAnnotation(expr->returnAnnotation->tailType, module);
if (annot && containsAny(*annot))
{
return true;
}
}
return false;
}
2024-08-02 00:25:12 +01:00
bool AnyTypeSummary::isAnyCast(const Scope* scope, AstExpr* expr, const Module* module, NotNull<BuiltinTypes> builtinTypes)
2024-07-26 01:10:42 +01:00
{
if (auto cast = expr->as<AstExprTypeAssertion>())
{
auto annot = lookupAnnotation(cast->annotation, module, builtinTypes);
if (containsAny(annot))
{
return true;
}
}
return false;
}
2024-08-02 00:25:12 +01:00
TypeId AnyTypeSummary::lookupAnnotation(AstType* annotation, const Module* module, NotNull<BuiltinTypes> builtintypes)
2024-07-26 01:10:42 +01:00
{
if (FFlag::DebugLuauMagicTypes)
{
if (auto ref = annotation->as<AstTypeReference>(); ref && ref->parameters.size > 0)
{
if (auto ann = ref->parameters.data[0].type)
{
TypeId argTy = lookupAnnotation(ref->parameters.data[0].type, module, builtintypes);
return follow(argTy);
}
}
}
2024-08-02 00:25:12 +01:00
const TypeId* ty = module->astResolvedTypes.find(annotation);
2024-07-26 01:10:42 +01:00
if (ty)
return checkForTypeFunctionInhabitance(follow(*ty), annotation->location);
else
return checkForTypeFunctionInhabitance(builtintypes->errorRecoveryType(), annotation->location);
}
2024-08-02 00:25:12 +01:00
TypeId AnyTypeSummary::checkForTypeFunctionInhabitance(const TypeId instance, const Location location)
2024-07-26 01:10:42 +01:00
{
if (seenTypeFunctionInstances.find(instance))
return instance;
seenTypeFunctionInstances.insert(instance);
return instance;
}
2024-08-02 00:25:12 +01:00
std::optional<TypePackId> AnyTypeSummary::lookupPackAnnotation(AstTypePack* annotation, const Module* module)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
const TypePackId* tp = module->astResolvedTypePacks.find(annotation);
2024-07-26 01:10:42 +01:00
if (tp != nullptr)
return {follow(*tp)};
return {};
}
bool AnyTypeSummary::containsAny(TypeId typ)
{
typ = follow(typ);
if (auto t = seen.find(typ); t && !*t)
{
return false;
}
seen[typ] = false;
RecursionCounter counter{&recursionCount};
if (recursionCount >= FInt::LuauAnySummaryRecursionLimit)
{
return false;
}
bool found = false;
if (auto ty = get<AnyType>(typ))
{
found = true;
}
else if (auto ty = get<UnknownType>(typ))
{
found = true;
}
else if (auto ty = get<TableType>(typ))
{
for (auto& [_name, prop] : ty->props)
{
if (FFlag::DebugLuauDeferredConstraintResolution)
{
if (auto newT = follow(prop.readTy))
{
if (containsAny(*newT))
found = true;
}
else if (auto newT = follow(prop.writeTy))
{
if (containsAny(*newT))
found = true;
}
}
else
{
if (containsAny(prop.type()))
found = true;
}
}
}
else if (auto ty = get<IntersectionType>(typ))
{
for (auto part : ty->parts)
{
if (containsAny(part))
{
found = true;
}
}
}
else if (auto ty = get<UnionType>(typ))
{
for (auto option : ty->options)
{
if (containsAny(option))
{
found = true;
}
}
}
else if (auto ty = get<FunctionType>(typ))
{
if (containsAny(ty->argTypes))
found = true;
else if (containsAny(ty->retTypes))
found = true;
}
seen[typ] = found;
return found;
}
bool AnyTypeSummary::containsAny(TypePackId typ)
{
typ = follow(typ);
if (auto t = seen.find(typ); t && !*t)
{
return false;
}
seen[typ] = false;
auto [head, tail] = flatten(typ);
bool found = false;
for (auto tp : head)
{
if (containsAny(tp))
found = true;
}
if (tail)
{
if (auto vtp = get<VariadicTypePack>(tail))
{
if (auto ty = get<AnyType>(follow(vtp->ty)))
{
found = true;
}
}
else if (auto tftp = get<TypeFunctionInstanceTypePack>(tail))
{
for (TypePackId tp : tftp->packArguments)
{
if (containsAny(tp))
{
found = true;
}
}
for (TypeId t : tftp->typeArguments)
{
if (containsAny(t))
{
found = true;
}
}
}
}
seen[typ] = found;
return found;
}
2024-08-02 00:25:12 +01:00
const Scope* AnyTypeSummary::findInnerMostScope(const Location location, const Module* module)
2024-07-26 01:10:42 +01:00
{
2024-08-02 00:25:12 +01:00
const Scope* bestScope = module->getModuleScope().get();
2024-07-26 01:10:42 +01:00
bool didNarrow = false;
do
{
didNarrow = false;
for (auto scope : bestScope->children)
{
if (scope->location.encloses(location))
{
bestScope = scope.get();
didNarrow = true;
break;
}
}
} while (didNarrow && bestScope->children.size() > 0);
return bestScope;
}
2024-08-02 00:25:12 +01:00
std::optional<AstExpr*> AnyTypeSummary::matchRequire(const AstExprCall& call)
{
const char* require = "require";
if (call.args.size != 1)
return std::nullopt;
const AstExprGlobal* funcAsGlobal = call.func->as<AstExprGlobal>();
if (!funcAsGlobal || funcAsGlobal->name != require)
return std::nullopt;
if (call.args.size != 1)
return std::nullopt;
return call.args.data[0];
}
AstNode* AnyTypeSummary::getNode(AstStatBlock* root, AstNode* node)
{
FindReturnAncestry finder(node, root->location.end);
root->visit(&finder);
if (!finder.currNode)
finder.currNode = node;
LUAU_ASSERT(finder.found && finder.currNode);
return finder.currNode;
}
bool AnyTypeSummary::FindReturnAncestry::visit(AstStatLocalFunction* node)
{
currNode = node;
return !found;
}
bool AnyTypeSummary::FindReturnAncestry::visit(AstStatFunction* node)
{
currNode = node;
return !found;
}
bool AnyTypeSummary::FindReturnAncestry::visit(AstType* node)
{
return !found;
}
bool AnyTypeSummary::FindReturnAncestry::visit(AstNode* node)
{
if (node == stat)
{
found = true;
}
if (node->location.end == rootEnd && stat->location.end >= rootEnd)
{
currNode = node;
found = true;
}
return !found;
}
2024-07-26 01:10:42 +01:00
AnyTypeSummary::TypeInfo::TypeInfo(Pattern code, std::string node, TelemetryTypePair type)
: code(code)
, node(node)
, type(type)
{
}
2024-08-02 00:25:12 +01:00
AnyTypeSummary::FindReturnAncestry::FindReturnAncestry(AstNode* stat, Position rootEnd)
: stat(stat)
, rootEnd(rootEnd)
{
}
2024-07-26 01:10:42 +01:00
AnyTypeSummary::AnyTypeSummary() {}
} // namespace Luau