luau/Analysis/src/IostreamHelpers.cpp
Junseo Yoo b6b74b4425
Sync to upstream/release/634 (#1325)
# What's Changed?

- Performance improvement in the old solver
- Bugfixes in the new solver

## Old Solver

- Mark types that do not need instantiation when being exported to
prevent unnecessary work from being done

## New Solver

- Refactored instances of "type family" with "type function"
- Index-out-of-bounds bug fix in the resolution resolver
- Subtyping reasonings are merged only if all failed

---
### Internal Contributors

Co-authored-by: Aaron Weiss <aaronweiss@roblox.com>
Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>

---------

Co-authored-by: Aaron Weiss <aaronweiss@roblox.com>
Co-authored-by: Alexander McCord <amccord@roblox.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Vighnesh <vvijay@roblox.com>
Co-authored-by: Aviral Goel <agoel@roblox.com>
Co-authored-by: David Cope <dcope@roblox.com>
Co-authored-by: Lily Brown <lbrown@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-07-12 10:03:36 -07:00

319 lines
12 KiB
C++

// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/IostreamHelpers.h"
#include "Luau/ToString.h"
#include "Luau/TypePath.h"
namespace Luau
{
std::ostream& operator<<(std::ostream& stream, const Position& position)
{
return stream << "{ line = " << position.line << ", col = " << position.column << " }";
}
std::ostream& operator<<(std::ostream& stream, const Location& location)
{
return stream << "Location { " << location.begin << ", " << location.end << " }";
}
std::ostream& operator<<(std::ostream& stream, const AstName& name)
{
if (name.value)
return stream << name.value;
else
return stream << "<empty>";
}
template<typename T>
static void errorToString(std::ostream& stream, const T& err)
{
if constexpr (false)
{
}
else if constexpr (std::is_same_v<T, TypeMismatch>)
stream << "TypeMismatch { " << toString(err.wantedType) << ", " << toString(err.givenType) << " }";
else if constexpr (std::is_same_v<T, UnknownSymbol>)
stream << "UnknownSymbol { " << err.name << " , context " << err.context << " }";
else if constexpr (std::is_same_v<T, UnknownProperty>)
stream << "UnknownProperty { " << toString(err.table) << ", key = " << err.key << " }";
else if constexpr (std::is_same_v<T, NotATable>)
stream << "NotATable { " << toString(err.ty) << " }";
else if constexpr (std::is_same_v<T, CannotExtendTable>)
stream << "CannotExtendTable { " << toString(err.tableType) << ", context " << err.context << ", prop \"" << err.prop << "\" }";
else if constexpr (std::is_same_v<T, OnlyTablesCanHaveMethods>)
stream << "OnlyTablesCanHaveMethods { " << toString(err.tableType) << " }";
else if constexpr (std::is_same_v<T, DuplicateTypeDefinition>)
stream << "DuplicateTypeDefinition { " << err.name << " }";
else if constexpr (std::is_same_v<T, CountMismatch>)
stream << "CountMismatch { expected " << err.expected << ", got " << err.actual << ", context " << err.context << " }";
else if constexpr (std::is_same_v<T, FunctionDoesNotTakeSelf>)
stream << "FunctionDoesNotTakeSelf { }";
else if constexpr (std::is_same_v<T, FunctionRequiresSelf>)
stream << "FunctionRequiresSelf { }";
else if constexpr (std::is_same_v<T, OccursCheckFailed>)
stream << "OccursCheckFailed { }";
else if constexpr (std::is_same_v<T, UnknownRequire>)
stream << "UnknownRequire { " << err.modulePath << " }";
else if constexpr (std::is_same_v<T, IncorrectGenericParameterCount>)
{
stream << "IncorrectGenericParameterCount { name = " << err.name;
if (!err.typeFun.typeParams.empty() || !err.typeFun.typePackParams.empty())
{
stream << "<";
bool first = true;
for (auto param : err.typeFun.typeParams)
{
if (first)
first = false;
else
stream << ", ";
stream << toString(param.ty);
}
for (auto param : err.typeFun.typePackParams)
{
if (first)
first = false;
else
stream << ", ";
stream << toString(param.tp);
}
stream << ">";
}
stream << ", typeFun = " << toString(err.typeFun.type) << ", actualCount = " << err.actualParameters << " }";
}
else if constexpr (std::is_same_v<T, SyntaxError>)
stream << "SyntaxError { " << err.message << " }";
else if constexpr (std::is_same_v<T, CodeTooComplex>)
stream << "CodeTooComplex {}";
else if constexpr (std::is_same_v<T, UnificationTooComplex>)
stream << "UnificationTooComplex {}";
else if constexpr (std::is_same_v<T, UnknownPropButFoundLikeProp>)
{
stream << "UnknownPropButFoundLikeProp { key = '" << err.key << "', suggested = { ";
bool first = true;
for (Name name : err.candidates)
{
if (first)
first = false;
else
stream << ", ";
stream << "'" << name << "'";
}
stream << " }, table = " << toString(err.table) << " } ";
}
else if constexpr (std::is_same_v<T, GenericError>)
stream << "GenericError { " << err.message << " }";
else if constexpr (std::is_same_v<T, InternalError>)
stream << "InternalError { " << err.message << " }";
else if constexpr (std::is_same_v<T, CannotCallNonFunction>)
stream << "CannotCallNonFunction { " << toString(err.ty) << " }";
else if constexpr (std::is_same_v<T, ExtraInformation>)
stream << "ExtraInformation { " << err.message << " }";
else if constexpr (std::is_same_v<T, DeprecatedApiUsed>)
stream << "DeprecatedApiUsed { " << err.symbol << ", useInstead = " << err.useInstead << " }";
else if constexpr (std::is_same_v<T, ModuleHasCyclicDependency>)
{
stream << "ModuleHasCyclicDependency {";
bool first = true;
for (const ModuleName& name : err.cycle)
{
if (first)
first = false;
else
stream << ", ";
stream << name;
}
stream << "}";
}
else if constexpr (std::is_same_v<T, IllegalRequire>)
stream << "IllegalRequire { " << err.moduleName << ", reason = " << err.reason << " }";
else if constexpr (std::is_same_v<T, FunctionExitsWithoutReturning>)
stream << "FunctionExitsWithoutReturning {" << toString(err.expectedReturnType) << "}";
else if constexpr (std::is_same_v<T, DuplicateGenericParameter>)
stream << "DuplicateGenericParameter { " + err.parameterName + " }";
else if constexpr (std::is_same_v<T, CannotInferBinaryOperation>)
stream << "CannotInferBinaryOperation { op = " + toString(err.op) + ", suggested = '" +
(err.suggestedToAnnotate ? *err.suggestedToAnnotate : "") + "', kind "
<< err.kind << "}";
else if constexpr (std::is_same_v<T, MissingProperties>)
{
stream << "MissingProperties { superType = '" << toString(err.superType) << "', subType = '" << toString(err.subType) << "', properties = { ";
bool first = true;
for (Name name : err.properties)
{
if (first)
first = false;
else
stream << ", ";
stream << "'" << name << "'";
}
stream << " }, context " << err.context << " } ";
}
else if constexpr (std::is_same_v<T, SwappedGenericTypeParameter>)
stream << "SwappedGenericTypeParameter { name = '" + err.name + "', kind = " + std::to_string(err.kind) + " }";
else if constexpr (std::is_same_v<T, OptionalValueAccess>)
stream << "OptionalValueAccess { optional = '" + toString(err.optional) + "' }";
else if constexpr (std::is_same_v<T, MissingUnionProperty>)
{
stream << "MissingUnionProperty { type = '" + toString(err.type) + "', missing = { ";
bool first = true;
for (auto ty : err.missing)
{
if (first)
first = false;
else
stream << ", ";
stream << "'" << toString(ty) << "'";
}
stream << " }, key = '" + err.key + "' }";
}
else if constexpr (std::is_same_v<T, TypesAreUnrelated>)
stream << "TypesAreUnrelated { left = '" + toString(err.left) + "', right = '" + toString(err.right) + "' }";
else if constexpr (std::is_same_v<T, NormalizationTooComplex>)
stream << "NormalizationTooComplex { }";
else if constexpr (std::is_same_v<T, TypePackMismatch>)
stream << "TypePackMismatch { wanted = '" + toString(err.wantedTp) + "', given = '" + toString(err.givenTp) + "' }";
else if constexpr (std::is_same_v<T, DynamicPropertyLookupOnClassesUnsafe>)
stream << "DynamicPropertyLookupOnClassesUnsafe { " << toString(err.ty) << " }";
else if constexpr (std::is_same_v<T, UninhabitedTypeFunction>)
stream << "UninhabitedTypeFunction { " << toString(err.ty) << " }";
else if constexpr (std::is_same_v<T, ExplicitFunctionAnnotationRecommended>)
{
std::string recArgs = "[";
for (auto [s, t] : err.recommendedArgs)
recArgs += " " + s + ": " + toString(t);
recArgs += " ]";
stream << "ExplicitFunctionAnnotationRecommended { recommmendedReturn = '" + toString(err.recommendedReturn) +
"', recommmendedArgs = " + recArgs + "}";
}
else if constexpr (std::is_same_v<T, UninhabitedTypePackFunction>)
stream << "UninhabitedTypePackFunction { " << toString(err.tp) << " }";
else if constexpr (std::is_same_v<T, WhereClauseNeeded>)
stream << "WhereClauseNeeded { " << toString(err.ty) << " }";
else if constexpr (std::is_same_v<T, PackWhereClauseNeeded>)
stream << "PackWhereClauseNeeded { " << toString(err.tp) << " }";
else if constexpr (std::is_same_v<T, CheckedFunctionCallError>)
stream << "CheckedFunctionCallError { expected = '" << toString(err.expected) << "', passed = '" << toString(err.passed)
<< "', checkedFunctionName = " << err.checkedFunctionName << ", argumentIndex = " << std::to_string(err.argumentIndex) << " }";
else if constexpr (std::is_same_v<T, NonStrictFunctionDefinitionError>)
stream << "NonStrictFunctionDefinitionError { functionName = '" + err.functionName + "', argument = '" + err.argument +
"', argumentType = '" + toString(err.argumentType) + "' }";
else if constexpr (std::is_same_v<T, PropertyAccessViolation>)
stream << "PropertyAccessViolation { table = " << toString(err.table) << ", prop = '" << err.key << "', context = " << err.context << " }";
else if constexpr (std::is_same_v<T, CheckedFunctionIncorrectArgs>)
stream << "CheckedFunction { functionName = '" + err.functionName + ", expected = " + std::to_string(err.expected) +
", actual = " + std::to_string(err.actual) + "}";
else if constexpr (std::is_same_v<T, UnexpectedTypeInSubtyping>)
stream << "UnexpectedTypeInSubtyping { ty = '" + toString(err.ty) + "' }";
else if constexpr (std::is_same_v<T, UnexpectedTypePackInSubtyping>)
stream << "UnexpectedTypePackInSubtyping { tp = '" + toString(err.tp) + "' }";
else if constexpr (std::is_same_v<T, CannotAssignToNever>)
{
stream << "CannotAssignToNever { rvalueType = '" << toString(err.rhsType) << "', reason = '" << err.reason << "', cause = { ";
bool first = true;
for (TypeId ty : err.cause)
{
if (first)
first = false;
else
stream << ", ";
stream << "'" << toString(ty) << "'";
}
stream << " } } ";
}
else
static_assert(always_false_v<T>, "Non-exhaustive type switch");
}
std::ostream& operator<<(std::ostream& stream, const CannotAssignToNever::Reason& reason)
{
switch (reason)
{
case CannotAssignToNever::Reason::PropertyNarrowed:
return stream << "PropertyNarrowed";
default:
return stream << "UnknownReason";
}
}
std::ostream& operator<<(std::ostream& stream, const TypeErrorData& data)
{
auto cb = [&](const auto& e) {
return errorToString(stream, e);
};
visit(cb, data);
return stream;
}
std::ostream& operator<<(std::ostream& stream, const TypeError& error)
{
return stream << "TypeError { \"" << error.moduleName << "\", " << error.location << ", " << error.data << " }";
}
std::ostream& operator<<(std::ostream& stream, const TableState& tv)
{
return stream << static_cast<std::underlying_type<TableState>::type>(tv);
}
std::ostream& operator<<(std::ostream& stream, const Type& tv)
{
return stream << toString(tv);
}
std::ostream& operator<<(std::ostream& stream, const TypePackVar& tv)
{
return stream << toString(tv);
}
std::ostream& operator<<(std::ostream& stream, TypeId ty)
{
// we commonly use a null pointer when a type may not be present; we need to
// account for that here.
if (!ty)
return stream << "<nullptr>";
return stream << toString(ty);
}
std::ostream& operator<<(std::ostream& stream, TypePackId tp)
{
// we commonly use a null pointer when a type may not be present; we need to
// account for that here.
if (!tp)
return stream << "<nullptr>";
return stream << toString(tp);
}
namespace TypePath
{
std::ostream& operator<<(std::ostream& stream, const Path& path)
{
return stream << toString(path);
}
} // namespace TypePath
} // namespace Luau