2024-07-26 08:10:42 +08:00
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
# include "Luau/AstQuery.h"
# include "Luau/BuiltinDefinitions.h"
# include "Luau/RequireTracer.h"
# include "Fixture.h"
# include "doctest.h"
# include <algorithm>
using namespace Luau ;
2024-08-02 07:25:12 +08:00
using Pattern = AnyTypeSummary : : Pattern ;
2024-07-26 08:10:42 +08:00
LUAU_FASTFLAG ( DebugLuauDeferredConstraintResolution )
LUAU_FASTFLAG ( DebugLuauFreezeArena ) ;
LUAU_FASTFLAG ( DebugLuauMagicTypes ) ;
LUAU_FASTFLAG ( StudioReportLuauAny ) ;
2024-08-02 07:25:12 +08:00
struct ATSFixture : BuiltinsFixture
2024-07-26 08:10:42 +08:00
{
ScopedFastFlag sff { FFlag : : DebugLuauDeferredConstraintResolution , true } ;
ATSFixture ( )
{
addGlobalBinding ( frontend . globals , " game " , builtinTypes - > anyType , " @test " ) ;
addGlobalBinding ( frontend . globals , " script " , builtinTypes - > anyType , " @test " ) ;
}
} ;
TEST_SUITE_BEGIN ( " AnyTypeSummaryTest " ) ;
TEST_CASE_FIXTURE ( ATSFixture , " var_typepack_any " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
type A = ( number , string ) - > . . . any
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " type A = (number, string)->( ...any) " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " export_alias " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
export type t8 < t8 > = t0 & ( < t0 . . . > ( true | any ) - > ( ' ' ) )
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 1 , result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " export type t8<t8> = t0 &(<t0 ...>(true | any)->('')) " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " var_typepack_any_gen_table " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
type Pair < T > = { first : T , second : any }
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " type Pair<T> = {first: T, second: any} " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " assign_uneq " )
{
fileResolver . source [ " game/Gui/Modules/B " ] = R " (
local function greetings ( name : string )
return " Hello, " . . name , nil
end
local x , y = greetings ( " Dibri " )
local x , y = greetings ( " Dibri " ) , nil
local x , y , z = greetings ( " Dibri " ) - - mismatch
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/B " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 1 , result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/B " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 0 ) ;
}
}
TEST_CASE_FIXTURE ( ATSFixture , " var_typepack_any_gen " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
- - type Pair < T > = ( boolean , string , . . . any ) - > { T } - - type aliases with generics / pack do not seem to be processed ?
type Pair < T > = ( boolean , T ) - > . . . any
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " type Pair<T> = (boolean, T)->( ...any) " ) ;
}
}
TEST_CASE_FIXTURE ( ATSFixture , " typeof_any_in_func " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local function f ( )
local a : any = 1
local b : typeof ( a ) = 1
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 2 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : VarAnnot ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function f() \n local a: any = 1 \n local b: typeof(a) = 1 \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " generic_types " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local function foo < A > ( a : ( . . . A ) - > any , . . . : A )
return a ( . . . )
end
local function addNumbers ( num1 , num2 )
local result = num1 + num2
return result
end
foo ( addNumbers )
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
2024-08-02 07:25:12 +08:00
2024-07-26 08:10:42 +08:00
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 3 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 1 ] . code = = Pattern : : FuncApp ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function foo<A>(a: (...A)->( any),...: A) \n return a(...) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " no_annot " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local character = script . Parent
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 0 ) ;
}
}
TEST_CASE_FIXTURE ( ATSFixture , " if_any " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
function f ( x : any )
if not x then
x = {
y = math . random ( 0 , 2 ^ 31 - 1 ) ,
left = nil ,
right = nil
}
else
local expected = x * 5
end
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " function f(x: any) \n if not x then \n x = { \n y = math.random(0, 2^31-1), \n left = nil, \n right = nil \n } \n else \n local expected = x * 5 \n end \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " variadic_any " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
2024-08-02 07:25:12 +08:00
local function f ( ) : ( number , . . . any )
2024-07-26 08:10:42 +08:00
return 1 , 5
end
local x , y , z = f ( ) - - not catching this any because no annot
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncRet ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function f(): (number, ...any) \n return 1, 5 \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " type_alias_intersection " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
type XCoord = { x : number }
type YCoord = { y : any }
type Vector2 = XCoord & YCoord - - table type intersections do not get normalized
local vec2 : Vector2 = { x = 1 , y = 2 }
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 3 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 2 ] . code = = Pattern : : VarAnnot ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 2 ] . node = = " local vec2: Vector2 = {x = 1, y = 2} " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " var_func_arg " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local function f ( . . . : any )
end
local function f ( x : number ? , y , z : any )
end
function f ( x : number ? , y , z : any )
end
function f ( . . . : any )
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 4 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : VarAny ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function f(...: any) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " var_func_apps " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local function f ( . . . : any )
end
f ( " string " , 123 )
f ( " string " )
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 3 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : VarAny ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function f(...: any) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " CannotExtendTable " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local CAR_COLLISION_GROUP = " Car "
- - Set the car collision group
for _ , descendant in carTemplate : GetDescendants ( ) do
if descendant : IsA ( " BasePart " ) then
descendant . CollisionGroup = CAR_COLLISION_GROUP
end
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 3 , result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 0 ) ;
}
}
TEST_CASE_FIXTURE ( ATSFixture , " unknown_symbol " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local function manageRace ( raceContainer : Model )
RaceManager . new ( raceContainer )
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 2 , result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
2024-08-02 07:25:12 +08:00
2024-07-26 08:10:42 +08:00
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 2 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function manageRace(raceContainer: Model) \n RaceManager.new(raceContainer) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " racing_3_short " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local CollectionService = game : GetService ( " CollectionService " )
local RaceManager = require ( script . RaceManager )
local RACE_TAG = " Race "
local function manageRace ( raceContainer : Model )
RaceManager . new ( raceContainer )
end
local function initialize ( )
CollectionService : GetInstanceAddedSignal ( RACE_TAG ) : Connect ( manageRace )
for _ , raceContainer in CollectionService : GetTagged ( RACE_TAG ) do
manageRace ( raceContainer )
end
end
initialize ( )
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 2 , result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 5 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function manageRace(raceContainer: Model) \n RaceManager.new(raceContainer) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " racing_collision_2 " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local PhysicsService = game : GetService ( " PhysicsService " )
local ReplicatedStorage = game : GetService ( " ReplicatedStorage " )
local safePlayerAdded = require ( script . safePlayerAdded )
local CAR_COLLISION_GROUP = " Car "
local CHARACTER_COLLISION_GROUP = " Character "
local carTemplate = ReplicatedStorage . Car
local function onCharacterAdded ( character : Model )
- - Set the collision group for any parts that are added to the character
character . DescendantAdded : Connect ( function ( descendant )
if descendant : IsA ( " BasePart " ) then
descendant . CollisionGroup = CHARACTER_COLLISION_GROUP
end
end )
- - Set the collision group for any parts currently in the character
for _ , descendant in character : GetDescendants ( ) do
if descendant : IsA ( " BasePart " ) then
descendant . CollisionGroup = CHARACTER_COLLISION_GROUP
end
end
end
local function onPlayerAdded ( player : Player )
player . CharacterAdded : Connect ( onCharacterAdded )
if player . Character then
onCharacterAdded ( player . Character )
end
end
local function initialize ( )
- - Setup collision groups
PhysicsService : RegisterCollisionGroup ( CAR_COLLISION_GROUP )
PhysicsService : RegisterCollisionGroup ( CHARACTER_COLLISION_GROUP )
- - Stop the collision groups from colliding with each other
PhysicsService : CollisionGroupSetCollidable ( CAR_COLLISION_GROUP , CAR_COLLISION_GROUP , false )
PhysicsService : CollisionGroupSetCollidable ( CHARACTER_COLLISION_GROUP , CHARACTER_COLLISION_GROUP , false )
PhysicsService : CollisionGroupSetCollidable ( CAR_COLLISION_GROUP , CHARACTER_COLLISION_GROUP , false )
- - Set the car collision group
for _ , descendant in carTemplate : GetDescendants ( ) do
if descendant : IsA ( " BasePart " ) then
descendant . CollisionGroup = CAR_COLLISION_GROUP
end
end
- - Set character collision groups for all players
safePlayerAdded ( onPlayerAdded )
end
initialize ( )
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 5 , result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 11 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function onCharacterAdded(character: Model) \n \n character.DescendantAdded:Connect(function(descendant) \n if descendant:IsA('BasePart')then \n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP \n end \n end) \n \n \n for _, descendant in character:GetDescendants()do \n if descendant:IsA('BasePart')then \n descendant.CollisionGroup = CHARACTER_COLLISION_GROUP \n end \n end \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " racing_spawning_1 " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local CollectionService = game : GetService ( " CollectionService " )
local Players = game : GetService ( " Players " )
local spawnCar = require ( script . spawnCar )
local destroyPlayerCars = require ( script . destroyPlayerCars )
local spawnPromptTemplate = script . SpawnPrompt
local KIOSK_TAG = " CarSpawnKiosk "
local function setupKiosk ( kiosk : Model )
local spawnLocation = kiosk : FindFirstChild ( " SpawnLocation " )
assert ( spawnLocation , ` { kiosk : GetFullName ( ) } has no SpawnLocation part ` )
local promptPart = kiosk : FindFirstChild ( " Prompt " )
assert ( promptPart , ` { kiosk : GetFullName ( ) } has no Prompt part ` )
- - Hide the car spawn location
spawnLocation . Transparency = 1
- - Create a new prompt to spawn the car
local spawnPrompt = spawnPromptTemplate : Clone ( )
spawnPrompt . Parent = promptPart
spawnPrompt . Triggered : Connect ( function ( player : Player )
- - Remove any existing cars the player has spawned
destroyPlayerCars ( player )
- - Spawn a new car at the spawnLocation , owned by the player
spawnCar ( spawnLocation . CFrame , player )
end )
end
local function initialize ( )
- - Remove cars owned by players whenever they leave
Players . PlayerRemoving : Connect ( destroyPlayerCars )
- - Setup all car spawning kiosks
CollectionService : GetInstanceAddedSignal ( KIOSK_TAG ) : Connect ( setupKiosk )
for _ , kiosk in CollectionService : GetTagged ( KIOSK_TAG ) do
setupKiosk ( kiosk )
end
end
initialize ( )
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 5 , result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 7 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local function setupKiosk(kiosk: Model) \n local spawnLocation = kiosk:FindFirstChild('SpawnLocation') \n assert(spawnLocation, `{kiosk:GetFullName()} has no SpawnLocation part`) \n local promptPart = kiosk:FindFirstChild('Prompt') \n assert(promptPart, `{kiosk:GetFullName()} has no Prompt part`) \n \n \n spawnLocation.Transparency = 1 \n \n \n local spawnPrompt = spawnPromptTemplate:Clone() \n spawnPrompt.Parent = promptPart \n \n spawnPrompt.Triggered:Connect(function(player: Player) \n \n destroyPlayerCars(player) \n \n spawnCar(spawnLocation.CFrame, player) \n end) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " mutually_recursive_generic " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
- - ! strict
type T < a > = { f : a , g : U < a > }
type U < a > = { h : a , i : T < a > ? }
local x : T < number > = { f = 37 , g = { h = 5 , i = nil } }
x . g . i = x
local y : T < string > = { f = " hi " , g = { h = " lo " , i = nil } }
y . g . i = y
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 2 , result1 ) ;
2024-08-02 07:25:12 +08:00
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 0 ) ;
}
2024-07-26 08:10:42 +08:00
}
TEST_CASE_FIXTURE ( ATSFixture , " explicit_pack " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
type Foo < T . . . > = ( T . . . ) - > ( ) - - also want to see how these are used .
type Bar = Foo < ( number , any ) >
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " type Bar = Foo<(number, any)> " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " var_any_local " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local x = 2
local x : any = 2 , 3
local x : any , y = 1 , 2
local x : number , y : any , z , h : nil = 1 , nil
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 3 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : VarAnnot ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local x: any = 2, 3 " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " table_uses_any " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local x : any = 0
local y : number
local z = { x = x , y = y } - - not catching this
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : VarAnnot ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local x: any = 0 " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " typeof_any " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local x : any = 0
function some1 ( x : typeof ( x ) )
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 2 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 1 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " function some1(x: typeof(x)) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " table_type_assigned " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local x : { x : any ? } = { x = 1 }
local z : { x : any , y : number ? } - - not catching this
z . x = " bigfatlongstring "
z . y = nil
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 2 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 1 ] . code = = Pattern : : Assign ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " local x: { x: any?} = {x = 1} " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " simple_func_wo_ret " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
function some ( x : any )
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " function some(x: any) \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " simple_func_w_ret " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
function other ( y : number ) : any
return " gotcha! "
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncRet ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " function other(y: number): any \n return 'gotcha!' \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " nested_local " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
function cool ( y : number ) : number
local g : any = " gratatataaa "
return y
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : VarAnnot ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " function cool(y: number): number \n local g: any = 'gratatataaa' \n return y \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " generic_func " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
function reverse < T > ( a : { T } , b : any ) : { T }
return a
end
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 1 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : FuncArg ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " function reverse<T>(a: {T}, b: any): {T} \n return a \n end " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " type_alias_any " )
{
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
type Clear = any
local z : Clear = " zip "
) " ;
CheckResult result1 = frontend . check ( " game/Gui/Modules/A " ) ;
LUAU_REQUIRE_NO_ERRORS ( result1 ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/Gui/Modules/A " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 2 ) ;
2024-08-02 07:25:12 +08:00
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " type Clear = any " ) ;
2024-07-26 08:10:42 +08:00
}
}
TEST_CASE_FIXTURE ( ATSFixture , " multi_module_any " )
{
fileResolver . source [ " game/A " ] = R " (
export type MyFunction = ( number , string ) - > ( any )
) " ;
fileResolver . source [ " game/B " ] = R " (
local MyFunc = require ( script . Parent . A )
type Clear = any
local z : Clear = " zip "
) " ;
fileResolver . source [ " game/Gui/Modules/A " ] = R " (
local Modules = game : GetService ( ' Gui ' ) . Modules
local B = require ( Modules . B )
return { hello = B . hello }
) " ;
CheckResult result = frontend . check ( " game/B " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 1 , result ) ;
2024-08-02 07:25:12 +08:00
ModulePtr module = frontend . moduleResolver . getModule ( " game/B " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 2 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 0 ] . node = = " type Clear = any " ) ;
}
}
TEST_CASE_FIXTURE ( ATSFixture , " cast_on_cyclic_req " )
{
fileResolver . source [ " game/A " ] = R " (
local a = require ( script . Parent . B ) - - not resolving this module
export type MyFunction = ( number , string ) - > ( any )
) " ;
fileResolver . source [ " game/B " ] = R " (
local MyFunc = require ( script . Parent . A ) : : any
type Clear = any
local z : Clear = " zip "
) " ;
CheckResult result = frontend . check ( " game/B " ) ;
LUAU_REQUIRE_ERROR_COUNT ( 0 , result ) ;
ModulePtr module = frontend . moduleResolver . getModule ( " game/B " ) ;
if ( FFlag : : StudioReportLuauAny )
{
LUAU_ASSERT ( module - > ats . typeInfo . size ( ) = = 3 ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 1 ] . code = = Pattern : : Alias ) ;
LUAU_ASSERT ( module - > ats . typeInfo [ 1 ] . node = = " type Clear = any " ) ;
}
2024-07-26 08:10:42 +08:00
}
2024-08-02 07:25:12 +08:00
2024-07-26 08:10:42 +08:00
TEST_SUITE_END ( ) ;