Path: blob/master/Analysis/include/Luau/ConstraintGenerator.h
2727 views
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details1#pragma once23#include "Luau/Ast.h"4#include "Luau/Constraint.h"5#include "Luau/ConstraintSet.h"6#include "Luau/ControlFlow.h"7#include "Luau/DataFlowGraph.h"8#include "Luau/HashUtil.h"9#include "Luau/InsertionOrderedMap.h"10#include "Luau/Module.h"11#include "Luau/ModuleResolver.h"12#include "Luau/NotNull.h"13#include "Luau/Polarity.h"14#include "Luau/Refinement.h"15#include "Luau/Set.h"16#include "Luau/Symbol.h"17#include "Luau/TypeFwd.h"18#include "Luau/TypeIds.h"19#include "Luau/TypeUtils.h"2021#include <memory>22#include <vector>2324namespace Luau25{2627struct Scope;28using ScopePtr = std::shared_ptr<Scope>;2930struct DcrLogger;31struct TypeFunctionRuntime;3233struct Inference34{35TypeId ty = nullptr;36RefinementId refinement = nullptr;3738Inference() = default;3940explicit Inference(TypeId ty, RefinementId refinement = nullptr)41: ty(ty)42, refinement(refinement)43{44}45};4647struct InferencePack48{49TypePackId tp = nullptr;50std::vector<RefinementId> refinements;5152InferencePack() = default;5354explicit InferencePack(TypePackId tp, const std::vector<RefinementId>& refinements = {})55: tp(tp)56, refinements(refinements)57{58}59};6061struct Checkpoint62{63size_t offset = 0;64};6566struct ConstraintGenerator67{68// A list of all the scopes in the module. This vector holds ownership of the69// scope pointers; the scopes themselves borrow pointers to other scopes to70// define the scope hierarchy.71std::vector<std::pair<Location, ScopePtr>> scopes;7273ModulePtr module;74NotNull<BuiltinTypes> builtinTypes;75const NotNull<TypeArena> arena;76// The root scope of the module we're generating constraints for.77// This is null when the CG is initially constructed.78Scope* rootScope;7980TypeContext typeContext = TypeContext::Default;8182struct InferredBinding83{84Scope* scope;85Location location;86TypeIds types;87};8889// Some locals have multiple type states. We wish for Scope::bindings to90// map each local name onto the union of every type that the local can have91// over its lifetime, so we use this map to accumulate the set of types it92// might have.93//94// See the functions recordInferredBinding and fillInInferredBindings.95DenseHashMap<Symbol, InferredBinding> inferredBindings{{}};9697// Constraints that go straight to the solver.98std::vector<ConstraintPtr> constraints;99100// The set of all free types introduced during constraint generation.101TypeIds freeTypes;102103// Map a function's signature scope back to its signature type.104DenseHashMap<Scope*, TypeId> scopeToFunction{nullptr};105106// The private scope of type aliases for which the type parameters belong to.107DenseHashMap<const AstStatTypeAlias*, ScopePtr> astTypeAliasDefiningScopes{nullptr};108109NotNull<const DataFlowGraph> dfg;110RefinementArena refinementArena;111112int recursionCount = 0;113114// It is pretty uncommon for constraint generation to itself produce errors, but it can happen.115std::vector<TypeError> errors;116117// Needed to be able to enable error-suppression preservation for immediate refinements.118NotNull<Normalizer> normalizer;119120// Needed to register all available type functions for execution at later stages.121NotNull<TypeFunctionRuntime> typeFunctionRuntime;122DenseHashMap<const AstStatTypeFunction*, ScopePtr> astTypeFunctionEnvironmentScopes{nullptr};123124// Needed to resolve modules to make 'require' import types properly.125NotNull<ModuleResolver> moduleResolver;126// Occasionally constraint generation needs to produce an ICE.127const NotNull<InternalErrorReporter> ice;128129ScopePtr globalScope;130ScopePtr typeFunctionScope;131132std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope;133std::vector<RequireCycle> requireCycles;134135DenseHashMap<TypeId, TypeIds> localTypes{nullptr};136137DenseHashMap<AstExpr*, Inference> inferredExprCache{nullptr};138139DcrLogger* logger;140141bool recursionLimitMet = false;142143ConstraintGenerator(144ModulePtr module,145NotNull<Normalizer> normalizer,146NotNull<TypeFunctionRuntime> typeFunctionRuntime,147NotNull<ModuleResolver> moduleResolver,148NotNull<BuiltinTypes> builtinTypes,149NotNull<InternalErrorReporter> ice,150ScopePtr globalScope,151ScopePtr typeFunctionScope,152std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,153DcrLogger* logger,154NotNull<DataFlowGraph> dfg,155std::vector<RequireCycle> requireCycles156);157158ConstraintSet run(AstStatBlock* block);159ConstraintSet runOnFragment(const ScopePtr& resumeScope, AstStatBlock* block);160161/**162* The entry point to the ConstraintGenerator. This will construct a set163* of scopes, constraints, and free types that can be solved later.164* @param block the root block to generate constraints for.165*/166void visitModuleRoot(AstStatBlock* block);167168void visitFragmentRoot(const ScopePtr& resumeScope, AstStatBlock* block);169170private:171struct InteriorFreeTypes172{173std::vector<TypeId> types;174std::vector<TypePackId> typePacks;175};176177std::vector<InteriorFreeTypes> interiorFreeTypes;178179std::vector<TypeId> unionsToSimplify;180181Set<AstName> uninitializedGlobals{{}};182183Polarity polarity = Polarity::None;184185DenseHashMap<std::pair<TypeId, std::string>, TypeId, PairHash<TypeId, std::string>> propIndexPairsSeen{{nullptr, ""}};186187// Used to keep track of when we are inside a large table and should188// opt *not* to do type inference for singletons.189size_t largeTableDepth = 0;190191/**192* Fabricates a new free type belonging to a given scope.193* @param scope the scope the free type belongs to.194*/195TypeId freshType(const ScopePtr& scope, Polarity polarity = Polarity::Unknown);196197/**198* Fabricates a new free type pack belonging to a given scope.199* @param scope the scope the free type pack belongs to.200*/201TypePackId freshTypePack(const ScopePtr& scope, Polarity polarity = Polarity::Unknown);202203/**204* Allocate a new TypePack with the given head and tail.205*206* Avoids allocating 0-length type packs:207*208* If the head is non-empty, allocate and return a type pack with the given209* head and tail.210* If the head is empty and tail is non-empty, return *tail.211* If both the head and tail are empty, return an empty type pack.212*/213TypePackId addTypePack(std::vector<TypeId> head, std::optional<TypePackId> tail);214215/**216* Fabricates a scope that is a child of another scope.217* @param node the lexical node that the scope belongs to.218* @param parent the parent scope of the new scope. Must not be null.219*/220ScopePtr childScope(AstNode* node, const ScopePtr& parent);221222std::optional<TypeId> lookup(const ScopePtr& scope, Location location, DefId def, bool prototype = true);223224/**225* Adds a new constraint with no dependencies to a given scope.226* @param scope the scope to add the constraint to.227* @param cv the constraint variant to add.228* @return the pointer to the inserted constraint229*/230NotNull<Constraint> addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv);231232/**233* Adds a constraint to a given scope.234* @param scope the scope to add the constraint to. Must not be null.235* @param c the constraint to add.236* @return the pointer to the inserted constraint237*/238NotNull<Constraint> addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c);239240struct RefinementPartition241{242// Types that we want to intersect against the type of the expression.243std::vector<TypeId> discriminantTypes;244245// Sometimes the type we're discriminating against is implicitly nil.246bool shouldAppendNilType = false;247};248249using RefinementContext = InsertionOrderedMap<DefId, RefinementPartition>;250void unionRefinements(251const ScopePtr& scope,252Location location,253const RefinementContext& lhs,254const RefinementContext& rhs,255RefinementContext& dest,256std::vector<ConstraintV>* constraints257);258void computeRefinement(259const ScopePtr& scope,260Location location,261RefinementId refinement,262RefinementContext* refis,263bool sense,264bool eq,265std::vector<ConstraintV>* constraints266);267void applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement);268269LUAU_NOINLINE void checkAliases(const ScopePtr& scope, AstStatBlock* block);270271ControlFlow visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block);272273ControlFlow visit(const ScopePtr& scope, AstStat* stat);274ControlFlow visit(const ScopePtr& scope, AstStatBlock* block);275ControlFlow visit(const ScopePtr& scope, AstStatLocal* local);276ControlFlow visit(const ScopePtr& scope, AstStatFor* for_);277ControlFlow visit(const ScopePtr& scope, AstStatForIn* forIn);278ControlFlow visit(const ScopePtr& scope, AstStatWhile* while_);279ControlFlow visit(const ScopePtr& scope, AstStatRepeat* repeat);280ControlFlow visit(const ScopePtr& scope, AstStatLocalFunction* function);281ControlFlow visit(const ScopePtr& scope, AstStatFunction* function);282ControlFlow visit(const ScopePtr& scope, AstStatReturn* ret);283ControlFlow visit(const ScopePtr& scope, AstStatAssign* assign);284ControlFlow visit(const ScopePtr& scope, AstStatCompoundAssign* assign);285ControlFlow visit(const ScopePtr& scope, AstStatIf* ifStatement);286ControlFlow visit(const ScopePtr& scope, AstStatTypeAlias* alias);287ControlFlow visit(const ScopePtr& scope, AstStatTypeFunction* function);288ControlFlow visit(const ScopePtr& scope, AstStatDeclareGlobal* declareGlobal);289ControlFlow visit(const ScopePtr& scope, AstStatDeclareExternType* declareExternType);290ControlFlow visit(const ScopePtr& scope, AstStatDeclareFunction* declareFunction);291ControlFlow visit(const ScopePtr& scope, AstStatError* error);292293InferencePack checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<std::optional<TypeId>>& expectedTypes = {});294InferencePack checkPack(295const ScopePtr& scope,296AstExpr* expr,297const std::vector<std::optional<TypeId>>& expectedTypes = {},298bool generalize = true299);300301InferencePack checkPack(const ScopePtr& scope, AstExprCall* call);302InferencePack checkExprCall(303const ScopePtr& scope,304AstExprCall* call,305TypeId fnType,306Checkpoint funcBeginCheckpoint,307Checkpoint funcEndCheckpoint308);309310/**311* Checks an expression that is expected to evaluate to one type.312* @param scope the scope the expression is contained within.313* @param expr the expression to check.314* @param expectedType the type of the expression that is expected from its315* surrounding context. Used to implement bidirectional type checking.316* @param generalize If true, generalize any lambdas that are encountered.317* @return the type of the expression.318*/319Inference check(320const ScopePtr& scope,321AstExpr* expr,322std::optional<TypeId> expectedType = {},323bool forceSingleton = false,324bool generalize = true325);326327Inference check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton);328Inference check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional<TypeId> expectedType, bool forceSingleton);329Inference check(const ScopePtr& scope, AstExprLocal* local);330Inference check(const ScopePtr& scope, AstExprGlobal* global);331Inference checkIndexName(const ScopePtr& scope, const RefinementKey* key, AstExpr* indexee, const std::string& index, Location indexLocation);332Inference check(const ScopePtr& scope, AstExprIndexName* indexName);333Inference check(const ScopePtr& scope, AstExprIndexExpr* indexExpr);334Inference check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize);335Inference check(const ScopePtr& scope, AstExprUnary* unary);336Inference check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);337Inference checkAstExprBinary(338const ScopePtr& scope,339const Location& location,340AstExprBinary::Op op,341AstExpr* left,342AstExpr* right,343std::optional<TypeId> expectedType344);345Inference check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType);346Inference check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert);347Inference check(const ScopePtr& scope, AstExprInterpString* interpString);348Inference check(const ScopePtr& scope, AstExprInstantiate* explicitTypeInstantiation);349Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);350std::tuple<TypeId, TypeId, RefinementId> checkBinary(351const ScopePtr& scope,352AstExprBinary::Op op,353AstExpr* left,354AstExpr* right,355std::optional<TypeId> expectedType356);357358void visitLValue(const ScopePtr& scope, AstExpr* expr, TypeId rhsType);359void visitLValue(const ScopePtr& scope, AstExprLocal* local, TypeId rhsType);360void visitLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId rhsType);361void visitLValue(const ScopePtr& scope, AstExprIndexName* indexName, TypeId rhsType);362void visitLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr, TypeId rhsType);363364struct FunctionSignature365{366// The type of the function.367TypeId signature;368// The scope that encompasses the function's signature. May be nullptr369// if there was no need for a signature scope (the function has no370// generics).371ScopePtr signatureScope;372// The scope that encompasses the function's body. Is a child scope of373// signatureScope, if present.374ScopePtr bodyScope;375};376377FunctionSignature checkFunctionSignature(378const ScopePtr& parent,379AstExprFunction* fn,380std::optional<TypeId> expectedType = {},381std::optional<Location> originalName = {}382);383384/**385* Checks the body of a function expression.386* @param scope the interior scope of the body of the function.387* @param fn the function expression to check.388*/389void checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn);390391// Specializations of 'resolveType' below392TypeId resolveReferenceType(const ScopePtr& scope, AstType* ty, AstTypeReference* ref, bool inTypeArguments, bool replaceErrorWithFresh);393TypeId resolveTableType(const ScopePtr& scope, AstType* ty, AstTypeTable* tab, bool inTypeArguments, bool replaceErrorWithFresh);394TypeId resolveFunctionType(const ScopePtr& scope, AstType* ty, AstTypeFunction* fn, bool inTypeArguments, bool replaceErrorWithFresh);395396public:397/**398* Resolves a type from its AST annotation.399* @param scope the scope that the type annotation appears within.400* @param ty the AST annotation to resolve.401* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.402* @return the type of the AST annotation.403**/404TypeId resolveType(405const ScopePtr& scope,406AstType* ty,407bool inTypeArguments,408bool replaceErrorWithFresh = false,409Polarity initialPolarity = Polarity::Positive410);411412private:413// resolveType() is recursive, but we only want to invoke414// inferGenericPolarities() once at the very end. We thus isolate the415// recursive part of the algorithm to this internal helper.416TypeId resolveType_(const ScopePtr& scope, AstType* ty, bool inTypeArguments, bool replaceErrorWithFresh = false);417418/**419* Resolves a type pack from its AST annotation.420* @param scope the scope that the type annotation appears within.421* @param tp the AST annotation to resolve.422* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.423* @return the type pack of the AST annotation.424**/425TypePackId resolveTypePack(426const ScopePtr& scope,427AstTypePack* tp,428bool inTypeArguments,429bool replaceErrorWithFresh = false,430Polarity initialPolarity = Polarity::Positive431);432433// Inner helper for resolveTypePack434TypePackId resolveTypePack_(const ScopePtr& scope, AstTypePack* tp, bool inTypeArguments, bool replaceErrorWithFresh = false);435436/**437* Resolves a type pack from its AST annotation.438* @param scope the scope that the type annotation appears within.439* @param list the AST annotation to resolve.440* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.441* @return the type pack of the AST annotation.442**/443TypePackId resolveTypePack(444const ScopePtr& scope,445const AstTypeList& list,446bool inTypeArguments,447bool replaceErrorWithFresh = false,448Polarity initialPolarity = Polarity::Positive449);450451// Clip with LuauForwardPolarityForFunctionTypes452TypePackId resolveTypePack_DEPRECATED(453const ScopePtr& scope,454const AstTypeList& list,455bool inTypeArguments,456bool replaceErrorWithFresh = false,457Polarity initialPolarity = Polarity::Positive458);459460TypePackId resolveTypePack_(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments, bool replaceErrorWithFresh);461462/**463* Creates generic types given a list of AST definitions, resolving default464* types as required.465* @param scope the scope that the generics should belong to.466* @param generics the AST generics to create types for.467* @param useCache whether to use the generic type cache for the given468* scope.469* @param addTypes whether to add the types to the scope's470* privateTypeBindings map.471**/472std::vector<std::pair<Name, GenericTypeDefinition>> createGenerics(473const ScopePtr& scope,474AstArray<AstGenericType*> generics,475bool useCache = false,476bool addTypes = true477);478479/**480* Creates generic type packs given a list of AST definitions, resolving481* default type packs as required.482* @param scope the scope that the generic packs should belong to.483* @param generics the AST generics to create type packs for.484* @param useCache whether to use the generic type pack cache for the given485* scope.486* @param addTypes whether to add the types to the scope's487* privateTypePackBindings map.488**/489std::vector<std::pair<Name, GenericTypePackDefinition>> createGenericPacks(490const ScopePtr& scope,491AstArray<AstGenericTypePack*> generics,492bool useCache = false,493bool addTypes = true494);495496Inference flattenPack(const ScopePtr& scope, Location location, InferencePack pack);497498void reportError(Location location, TypeErrorData err);499void reportCodeTooComplex(Location location);500501// make a union type function of these two types502TypeId makeUnion(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);503504// Make a union type and add it to `unionsToSimplify`, ensuring that505// later we will attempt to simplify this union in order to keep types506// small.507TypeId makeUnion(std::vector<TypeId> options);508509// make an intersect type function of these two types510TypeId makeIntersect(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);511void prepopulateGlobalScopeForFragmentTypecheck(const ScopePtr& globalScope, const ScopePtr& resumeScope, AstStatBlock* program);512513/** Scan the program for global definitions.514*515* ConstraintGenerator needs to differentiate between globals and accesses to undefined symbols. Doing this "for516* real" in a general way is going to be pretty hard, so we are choosing not to tackle that yet. For now, we do an517* initial scan of the AST and note what globals are defined.518*/519void prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program);520521bool recordPropertyAssignment(TypeId ty);522523// Record the fact that a particular local has a particular type in at least524// one of its states.525void recordInferredBinding(AstLocal* local, TypeId ty);526527void fillInInferredBindings(const ScopePtr& globalScope, AstStatBlock* block);528529std::pair<std::vector<TypeId>, std::vector<TypePackId>> resolveTypeArguments(const ScopePtr& scope, const AstArray<AstTypeOrPack>& typeArguments);530531/** Given a function type annotation, return a vector describing the expected types of the calls to the function532* For example, calling a function with annotation ((number) -> string & ((string) -> number))533* yields a vector of size 1, with value: [number | string]534*/535std::vector<std::optional<TypeId>> getExpectedCallTypesForFunctionOverloads(const TypeId fnType);536537TypeId createTypeFunctionInstance(538const TypeFunction& function,539std::vector<TypeId> typeArguments,540std::vector<TypePackId> packArguments,541const ScopePtr& scope,542Location location543);544545TypeId simplifyUnion(const ScopePtr& scope, Location location, TypeId left, TypeId right);546547void updateRValueRefinements(const ScopePtr& scope, DefId def, TypeId ty) const;548void updateRValueRefinements(Scope* scope, DefId def, TypeId ty) const;549void resolveGenericDefaultParameters(const ScopePtr& defnScope, AstStatTypeAlias* alias, const TypeFun& fun);550};551552} // namespace Luau553554555