mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-02 01:23:48 +01:00
# General * Internally rename `ClassType` to `ExternType`. In definition files, the syntax to define these types has changed to `declare extern type Foo with prop: type end` * Add `luarequire_registermodule` to Luau.Require * Support yieldable Luau C functions calling other functions * Store return types as `AstTypePack*` on Ast nodes ## New Solver * Improve the logic that determines constraint dispatch ordering * Fix a crash in the type solver that arose when using multi-return functions with `string.format` * Fix https://github.com/luau-lang/luau/issues/1736 * Initial steps toward rethinking function generalization: * Instead of generalizing every type in a function all at once, we will instead generalize individual type variables once their bounds have been fully resolved. This will make it possible to properly interleave type function reduction and generalization. * Magic functions are no longer considered magical in cases where they are not explicitly called by the code. * The most prominent example of this is in `for..in` loops where the function call is part of the desugaring process. * Almost all magic functions work by directly inspecting the AST, so they can't work without an AST fragment anyway. * Further, none of the magic functions we have are usefully used in this way. Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Sora Kanosue <skanosue@roblox.com> Co-authored-by: Talha Pathan <tpathan@roblox.com> Co-authored-by: Varun Saini <vsaini@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
621 lines
13 KiB
C++
621 lines
13 KiB
C++
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
#pragma once
|
|
|
|
#include "Luau/Location.h"
|
|
#include "Luau/NotNull.h"
|
|
#include "Luau/Type.h"
|
|
#include "Luau/Variant.h"
|
|
#include "Luau/Ast.h"
|
|
|
|
#include <set>
|
|
|
|
namespace Luau
|
|
{
|
|
|
|
struct FileResolver;
|
|
struct TypeArena;
|
|
struct TypeError;
|
|
|
|
struct TypeMismatch
|
|
{
|
|
enum Context
|
|
{
|
|
CovariantContext,
|
|
InvariantContext
|
|
};
|
|
|
|
TypeMismatch() = default;
|
|
TypeMismatch(TypeId wantedType, TypeId givenType);
|
|
TypeMismatch(TypeId wantedType, TypeId givenType, std::string reason);
|
|
TypeMismatch(TypeId wantedType, TypeId givenType, std::string reason, std::optional<TypeError> error);
|
|
|
|
TypeMismatch(TypeId wantedType, TypeId givenType, Context context);
|
|
TypeMismatch(TypeId wantedType, TypeId givenType, std::string reason, Context context);
|
|
TypeMismatch(TypeId wantedType, TypeId givenType, std::string reason, std::optional<TypeError> error, Context context);
|
|
|
|
TypeId wantedType = nullptr;
|
|
TypeId givenType = nullptr;
|
|
Context context = CovariantContext;
|
|
|
|
std::string reason;
|
|
std::shared_ptr<TypeError> error;
|
|
|
|
bool operator==(const TypeMismatch& rhs) const;
|
|
};
|
|
|
|
struct UnknownSymbol
|
|
{
|
|
enum Context
|
|
{
|
|
Binding,
|
|
Type,
|
|
};
|
|
Name name;
|
|
Context context;
|
|
|
|
bool operator==(const UnknownSymbol& rhs) const;
|
|
};
|
|
|
|
struct UnknownProperty
|
|
{
|
|
TypeId table;
|
|
Name key;
|
|
|
|
bool operator==(const UnknownProperty& rhs) const;
|
|
};
|
|
|
|
struct NotATable
|
|
{
|
|
TypeId ty;
|
|
|
|
bool operator==(const NotATable& rhs) const;
|
|
};
|
|
|
|
struct CannotExtendTable
|
|
{
|
|
enum Context
|
|
{
|
|
Property,
|
|
Indexer,
|
|
Metatable
|
|
};
|
|
TypeId tableType;
|
|
Context context;
|
|
Name prop;
|
|
|
|
bool operator==(const CannotExtendTable& rhs) const;
|
|
};
|
|
|
|
struct OnlyTablesCanHaveMethods
|
|
{
|
|
TypeId tableType;
|
|
|
|
bool operator==(const OnlyTablesCanHaveMethods& rhs) const;
|
|
};
|
|
|
|
struct DuplicateTypeDefinition
|
|
{
|
|
Name name;
|
|
std::optional<Location> previousLocation;
|
|
|
|
bool operator==(const DuplicateTypeDefinition& rhs) const;
|
|
};
|
|
|
|
struct CountMismatch
|
|
{
|
|
enum Context
|
|
{
|
|
Arg,
|
|
FunctionResult,
|
|
ExprListResult,
|
|
Return,
|
|
};
|
|
size_t expected;
|
|
std::optional<size_t> maximum;
|
|
size_t actual;
|
|
Context context = Arg;
|
|
bool isVariadic = false;
|
|
std::string function;
|
|
|
|
bool operator==(const CountMismatch& rhs) const;
|
|
};
|
|
|
|
struct FunctionDoesNotTakeSelf
|
|
{
|
|
bool operator==(const FunctionDoesNotTakeSelf& rhs) const;
|
|
};
|
|
|
|
struct FunctionRequiresSelf
|
|
{
|
|
bool operator==(const FunctionRequiresSelf& rhs) const;
|
|
};
|
|
|
|
struct OccursCheckFailed
|
|
{
|
|
bool operator==(const OccursCheckFailed& rhs) const;
|
|
};
|
|
|
|
struct UnknownRequire
|
|
{
|
|
std::string modulePath;
|
|
|
|
bool operator==(const UnknownRequire& rhs) const;
|
|
};
|
|
|
|
struct IncorrectGenericParameterCount
|
|
{
|
|
Name name;
|
|
TypeFun typeFun;
|
|
size_t actualParameters;
|
|
size_t actualPackParameters;
|
|
|
|
bool operator==(const IncorrectGenericParameterCount& rhs) const;
|
|
};
|
|
|
|
struct SyntaxError
|
|
{
|
|
std::string message;
|
|
|
|
bool operator==(const SyntaxError& rhs) const;
|
|
};
|
|
|
|
struct CodeTooComplex
|
|
{
|
|
bool operator==(const CodeTooComplex&) const;
|
|
};
|
|
|
|
struct UnificationTooComplex
|
|
{
|
|
bool operator==(const UnificationTooComplex&) const;
|
|
};
|
|
|
|
// Could easily be folded into UnknownProperty with an extra field, std::set<Name> candidates.
|
|
// But for telemetry purposes, we want to have this be a distinct variant.
|
|
struct UnknownPropButFoundLikeProp
|
|
{
|
|
TypeId table;
|
|
Name key;
|
|
std::set<Name> candidates;
|
|
|
|
bool operator==(const UnknownPropButFoundLikeProp& rhs) const;
|
|
};
|
|
|
|
struct GenericError
|
|
{
|
|
std::string message;
|
|
|
|
bool operator==(const GenericError& rhs) const;
|
|
};
|
|
|
|
struct InternalError
|
|
{
|
|
std::string message;
|
|
|
|
bool operator==(const InternalError& rhs) const;
|
|
};
|
|
|
|
struct ConstraintSolvingIncompleteError
|
|
{
|
|
bool operator==(const ConstraintSolvingIncompleteError& rhs) const;
|
|
};
|
|
|
|
struct CannotCallNonFunction
|
|
{
|
|
TypeId ty;
|
|
|
|
bool operator==(const CannotCallNonFunction& rhs) const;
|
|
};
|
|
|
|
struct ExtraInformation
|
|
{
|
|
std::string message;
|
|
bool operator==(const ExtraInformation& rhs) const;
|
|
};
|
|
|
|
struct DeprecatedApiUsed
|
|
{
|
|
std::string symbol;
|
|
std::string useInstead;
|
|
bool operator==(const DeprecatedApiUsed& rhs) const;
|
|
};
|
|
|
|
struct ModuleHasCyclicDependency
|
|
{
|
|
std::vector<ModuleName> cycle;
|
|
bool operator==(const ModuleHasCyclicDependency& rhs) const;
|
|
};
|
|
|
|
struct FunctionExitsWithoutReturning
|
|
{
|
|
TypePackId expectedReturnType;
|
|
bool operator==(const FunctionExitsWithoutReturning& rhs) const;
|
|
};
|
|
|
|
struct IllegalRequire
|
|
{
|
|
std::string moduleName;
|
|
std::string reason;
|
|
|
|
bool operator==(const IllegalRequire& rhs) const;
|
|
};
|
|
|
|
struct MissingProperties
|
|
{
|
|
enum Context
|
|
{
|
|
Missing,
|
|
Extra
|
|
};
|
|
TypeId superType;
|
|
TypeId subType;
|
|
std::vector<Name> properties;
|
|
Context context = Missing;
|
|
|
|
bool operator==(const MissingProperties& rhs) const;
|
|
};
|
|
|
|
struct DuplicateGenericParameter
|
|
{
|
|
std::string parameterName;
|
|
|
|
bool operator==(const DuplicateGenericParameter& rhs) const;
|
|
};
|
|
|
|
struct CannotInferBinaryOperation
|
|
{
|
|
enum OpKind
|
|
{
|
|
Operation,
|
|
Comparison,
|
|
};
|
|
|
|
AstExprBinary::Op op;
|
|
std::optional<std::string> suggestedToAnnotate;
|
|
OpKind kind;
|
|
|
|
bool operator==(const CannotInferBinaryOperation& rhs) const;
|
|
};
|
|
|
|
struct SwappedGenericTypeParameter
|
|
{
|
|
enum Kind
|
|
{
|
|
Type,
|
|
Pack,
|
|
};
|
|
|
|
std::string name;
|
|
// What was `name` being used as?
|
|
Kind kind;
|
|
|
|
bool operator==(const SwappedGenericTypeParameter& rhs) const;
|
|
};
|
|
|
|
struct OptionalValueAccess
|
|
{
|
|
TypeId optional;
|
|
|
|
bool operator==(const OptionalValueAccess& rhs) const;
|
|
};
|
|
|
|
struct MissingUnionProperty
|
|
{
|
|
TypeId type;
|
|
std::vector<TypeId> missing;
|
|
Name key;
|
|
|
|
bool operator==(const MissingUnionProperty& rhs) const;
|
|
};
|
|
|
|
struct TypesAreUnrelated
|
|
{
|
|
TypeId left;
|
|
TypeId right;
|
|
|
|
bool operator==(const TypesAreUnrelated& rhs) const;
|
|
};
|
|
|
|
struct NormalizationTooComplex
|
|
{
|
|
bool operator==(const NormalizationTooComplex&) const
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
|
|
struct TypePackMismatch
|
|
{
|
|
TypePackId wantedTp;
|
|
TypePackId givenTp;
|
|
std::string reason;
|
|
|
|
bool operator==(const TypePackMismatch& rhs) const;
|
|
};
|
|
|
|
struct DynamicPropertyLookupOnExternTypesUnsafe
|
|
{
|
|
TypeId ty;
|
|
|
|
bool operator==(const DynamicPropertyLookupOnExternTypesUnsafe& rhs) const;
|
|
};
|
|
|
|
struct UninhabitedTypeFunction
|
|
{
|
|
TypeId ty;
|
|
|
|
bool operator==(const UninhabitedTypeFunction& rhs) const;
|
|
};
|
|
|
|
struct ExplicitFunctionAnnotationRecommended
|
|
{
|
|
std::vector<std::pair<std::string, TypeId>> recommendedArgs;
|
|
TypeId recommendedReturn;
|
|
bool operator==(const ExplicitFunctionAnnotationRecommended& rhs) const;
|
|
};
|
|
|
|
struct UninhabitedTypePackFunction
|
|
{
|
|
TypePackId tp;
|
|
|
|
bool operator==(const UninhabitedTypePackFunction& rhs) const;
|
|
};
|
|
|
|
struct WhereClauseNeeded
|
|
{
|
|
TypeId ty;
|
|
|
|
bool operator==(const WhereClauseNeeded& rhs) const;
|
|
};
|
|
|
|
struct PackWhereClauseNeeded
|
|
{
|
|
TypePackId tp;
|
|
|
|
bool operator==(const PackWhereClauseNeeded& rhs) const;
|
|
};
|
|
|
|
struct CheckedFunctionCallError
|
|
{
|
|
TypeId expected;
|
|
TypeId passed;
|
|
std::string checkedFunctionName;
|
|
// TODO: make this a vector<argumentIndices>
|
|
size_t argumentIndex;
|
|
bool operator==(const CheckedFunctionCallError& rhs) const;
|
|
};
|
|
|
|
struct NonStrictFunctionDefinitionError
|
|
{
|
|
std::string functionName;
|
|
std::string argument;
|
|
TypeId argumentType;
|
|
bool operator==(const NonStrictFunctionDefinitionError& rhs) const;
|
|
};
|
|
|
|
struct PropertyAccessViolation
|
|
{
|
|
TypeId table;
|
|
Name key;
|
|
|
|
enum
|
|
{
|
|
CannotRead,
|
|
CannotWrite
|
|
} context;
|
|
|
|
bool operator==(const PropertyAccessViolation& rhs) const;
|
|
};
|
|
|
|
struct CheckedFunctionIncorrectArgs
|
|
{
|
|
std::string functionName;
|
|
size_t expected;
|
|
size_t actual;
|
|
bool operator==(const CheckedFunctionIncorrectArgs& rhs) const;
|
|
};
|
|
|
|
struct CannotAssignToNever
|
|
{
|
|
// type of the rvalue being assigned
|
|
TypeId rhsType;
|
|
|
|
// Originating type.
|
|
std::vector<TypeId> cause;
|
|
|
|
enum class Reason
|
|
{
|
|
// when assigning to a property in a union of tables, the properties type
|
|
// is narrowed to the intersection of its type in each variant.
|
|
PropertyNarrowed,
|
|
};
|
|
|
|
Reason reason;
|
|
|
|
bool operator==(const CannotAssignToNever& rhs) const;
|
|
};
|
|
|
|
struct UnexpectedTypeInSubtyping
|
|
{
|
|
TypeId ty;
|
|
|
|
bool operator==(const UnexpectedTypeInSubtyping& rhs) const;
|
|
};
|
|
|
|
struct UnexpectedTypePackInSubtyping
|
|
{
|
|
TypePackId tp;
|
|
|
|
bool operator==(const UnexpectedTypePackInSubtyping& rhs) const;
|
|
};
|
|
|
|
struct UserDefinedTypeFunctionError
|
|
{
|
|
std::string message;
|
|
|
|
bool operator==(const UserDefinedTypeFunctionError& rhs) const;
|
|
};
|
|
|
|
struct ReservedIdentifier
|
|
{
|
|
std::string name;
|
|
|
|
bool operator==(const ReservedIdentifier& rhs) const;
|
|
};
|
|
|
|
using TypeErrorData = Variant<
|
|
TypeMismatch,
|
|
UnknownSymbol,
|
|
UnknownProperty,
|
|
NotATable,
|
|
CannotExtendTable,
|
|
OnlyTablesCanHaveMethods,
|
|
DuplicateTypeDefinition,
|
|
CountMismatch,
|
|
FunctionDoesNotTakeSelf,
|
|
FunctionRequiresSelf,
|
|
OccursCheckFailed,
|
|
UnknownRequire,
|
|
IncorrectGenericParameterCount,
|
|
SyntaxError,
|
|
CodeTooComplex,
|
|
UnificationTooComplex,
|
|
UnknownPropButFoundLikeProp,
|
|
GenericError,
|
|
InternalError,
|
|
ConstraintSolvingIncompleteError,
|
|
CannotCallNonFunction,
|
|
ExtraInformation,
|
|
DeprecatedApiUsed,
|
|
ModuleHasCyclicDependency,
|
|
IllegalRequire,
|
|
FunctionExitsWithoutReturning,
|
|
DuplicateGenericParameter,
|
|
CannotAssignToNever,
|
|
CannotInferBinaryOperation,
|
|
MissingProperties,
|
|
SwappedGenericTypeParameter,
|
|
OptionalValueAccess,
|
|
MissingUnionProperty,
|
|
TypesAreUnrelated,
|
|
NormalizationTooComplex,
|
|
TypePackMismatch,
|
|
DynamicPropertyLookupOnExternTypesUnsafe,
|
|
UninhabitedTypeFunction,
|
|
UninhabitedTypePackFunction,
|
|
WhereClauseNeeded,
|
|
PackWhereClauseNeeded,
|
|
CheckedFunctionCallError,
|
|
NonStrictFunctionDefinitionError,
|
|
PropertyAccessViolation,
|
|
CheckedFunctionIncorrectArgs,
|
|
UnexpectedTypeInSubtyping,
|
|
UnexpectedTypePackInSubtyping,
|
|
ExplicitFunctionAnnotationRecommended,
|
|
UserDefinedTypeFunctionError,
|
|
ReservedIdentifier>;
|
|
|
|
struct TypeErrorSummary
|
|
{
|
|
Location location;
|
|
ModuleName moduleName;
|
|
int code;
|
|
|
|
TypeErrorSummary(const Location& location, const ModuleName& moduleName, int code)
|
|
: location(location)
|
|
, moduleName(moduleName)
|
|
, code(code)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct TypeError
|
|
{
|
|
Location location;
|
|
ModuleName moduleName;
|
|
TypeErrorData data;
|
|
|
|
static int minCode();
|
|
int code() const;
|
|
|
|
TypeError() = default;
|
|
|
|
TypeError(const Location& location, const ModuleName& moduleName, const TypeErrorData& data)
|
|
: location(location)
|
|
, moduleName(moduleName)
|
|
, data(data)
|
|
{
|
|
}
|
|
|
|
TypeError(const Location& location, const TypeErrorData& data)
|
|
: TypeError(location, {}, data)
|
|
{
|
|
}
|
|
|
|
bool operator==(const TypeError& rhs) const;
|
|
|
|
TypeErrorSummary summary() const;
|
|
};
|
|
|
|
template<typename T>
|
|
const T* get(const TypeError& e)
|
|
{
|
|
return get_if<T>(&e.data);
|
|
}
|
|
|
|
template<typename T>
|
|
T* get(TypeError& e)
|
|
{
|
|
return get_if<T>(&e.data);
|
|
}
|
|
|
|
using ErrorVec = std::vector<TypeError>;
|
|
|
|
struct TypeErrorToStringOptions
|
|
{
|
|
FileResolver* fileResolver = nullptr;
|
|
};
|
|
|
|
std::string toString(const TypeError& error);
|
|
std::string toString(const TypeError& error, TypeErrorToStringOptions options);
|
|
|
|
bool containsParseErrorName(const TypeError& error);
|
|
|
|
// Copy any types named in the error into destArena.
|
|
void copyErrors(ErrorVec& errors, struct TypeArena& destArena, NotNull<BuiltinTypes> builtinTypes);
|
|
|
|
// Internal Compiler Error
|
|
struct InternalErrorReporter
|
|
{
|
|
std::function<void(const char*)> onInternalError;
|
|
std::string moduleName;
|
|
|
|
[[noreturn]] void ice(const std::string& message, const Location& location) const;
|
|
[[noreturn]] void ice(const std::string& message) const;
|
|
};
|
|
|
|
class InternalCompilerError : public std::exception
|
|
{
|
|
public:
|
|
explicit InternalCompilerError(const std::string& message)
|
|
: message(message)
|
|
{
|
|
}
|
|
explicit InternalCompilerError(const std::string& message, const std::string& moduleName)
|
|
: message(message)
|
|
, moduleName(moduleName)
|
|
{
|
|
}
|
|
explicit InternalCompilerError(const std::string& message, const std::string& moduleName, const Location& location)
|
|
: message(message)
|
|
, moduleName(moduleName)
|
|
, location(location)
|
|
{
|
|
}
|
|
virtual const char* what() const throw();
|
|
|
|
const std::string message;
|
|
const std::optional<std::string> moduleName;
|
|
const std::optional<Location> location;
|
|
};
|
|
|
|
} // namespace Luau
|