You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Luau type checking introduced in #908 works great already but there are a few things that could be improved. However, I think they require Luau improvements.
Here's the file in which I did a bunch of type checking experiments. It contains comments which things are still lacking.
--!strict--- This is an experiment how to do table merging while also merging (accumulating) the types.--- This could be very useful when merging partial mappins as the type checker could--- tell us if something is wrong or missing for the merged object to be a valid mapping.------ Turns out it's possible to some degree but with two caveats:------ 1. Doesn't work if the merging is done via metatable / operator overloading (bla + foo).--- 2. Even if using normal functions or self functions without metatable, it's a bit clunky--- due to the generic types not being able to be recursive with another type parameter.--------- We would need something along the lines of:--- - https://github.com/luau-lang/luau/issues/393--- - https://github.com/luau-lang/rfcs/pull/5localcommon= {}
typeArbitraryTable= { [any]: any }
--- Creates a shallow clone of a table.------ Typing not ideal because of https://github.com/luau-lang/luau/issues/392#issuecomment-1050344334functioncommon.clone<T>(t: T): Tiftype(t) ~="table" thenreturntendlocalnew_table= {}
fork, vint :: ArbitraryTabledonew_table[k] =vendreturnnew_table :: anyendtypeMergeable= { __add: <A, B>(t1: A, t2: B) ->A & B }
localmergeable: MergeabletypeMetatableMergeable=typeof(setmetatable({}, mergeable))
--- Makes it possible to merge this table with another one via "+" operator.------ Typing not ideal because of https://github.com/luau-lang/luau/issues/392#issuecomment-1050344334functioncommon.make_mergeable<V>(t: V): V & MetatableMergeableiftype(t) ~="table" thenreturnt :: anyendlocalmetatable= {
__add=common.merged,
}
setmetatable(t :: ArbitraryTable, metatable)
returntendtypeMerge<A>= { merge: <B>(self: A, other: B) ->A & B }
functioncommon.install_merge<A>(t: A): A & Merge<A>returnt :: anyend--- Caveat 2: We can't use Merge2<A&B> as a result but must add another type (non-recursive type).--- That also means the maximum number of merges is limited. Not a big issue though, we just need--- to write e.g. 10 Merge types and that's it.typeMerge2<A>= { merge: <B>(self: A, other: B) ->A & B & Merge3<A&B> }
typeMerge3<A>= { merge: <B>(self: A, other: B) ->A & B & Merge4<A&B>}
typeMerge4<A>= { merge: <B>(self: A, other: B) ->A & B }
functioncommon.install_merge2<A>(t: A): A & Merge2<A>returnt :: anyend--- Returns a new table that is the result of merging t2 into t1.------ Values in t2 have precedence.------ The result will be mergeable as well. This is good for "modifier chaining".------ Typing not ideal because of https://github.com/luau-lang/luau/issues/392#issuecomment-1050344334functioncommon.merged<A, B>(t1: A, t2: B): A & Biftype(t1) ~="table" ortype(t2) ~="table" thenreturnt1 :: anyendlocalresult=common.clone(t1 :: ArbitraryTable)
forkey, new_valueinpairs(t2 :: ArbitraryTable) dolocalold_value=result[key]
ifold_valueandtype(old_value) =="table" andtype(new_value) =="table" then-- Merge table value as wellresult[key] =common.merged(old_value, new_value) :: anyelse-- Simple use new valueresult[key] =new_valueendendreturncommon.make_mergeable(result :: any)
end-- Tests-- Try merging with function call (inconvenient): CHECKtypeCombined= {
foo: number,
bla: string,
man: number,
tan: number,
klos: string,
}
localbla= {
foo=5,
bla="asd"
}
localfoo= {
tan=4
}
localzubi= {
man=0,
bla="oho"
}
localending= {
klos="hallo"
}
localcombined: Combined=common.merged(common.merged(common.merged(bla, foo), zubi), ending)
-- Try merging with self method, no metatable: CHECKlocalmergeInstalled=common.install_merge(bla)
localcombined2: Combined=common.install_merge(common.install_merge(mergeInstalled:merge(foo)):merge(zubi)):merge(ending)
-- Try merging with self method, no metatable, result also mergable: CHECKlocalmergeInstalled2=common.install_merge2(bla)
localcombined2: Combined=mergeInstalled2:merge(foo):merge(zubi):merge(ending)
-- Try with metatable +: NONONOtypePartialMappingImpl<A>= {
__index: A,
__add: (PartialMappingImpl<A>, number) ->A,
}
typePartialMappingMetatable<A>=typeof(setmetatable(
{},
{} :: PartialMappingImpl<A>
))
typePartialMapping<A>=PartialMappingMetatable<A> & AlocalPartialMapping= {}
PartialMapping.__index=PartialMappingfunctionPartialMapping.new<A>(t: A): PartialMapping<A>-- local self = t-- return setmetatable(self, PartialMapping)returnt :: anyend-- function PartialMapping:__add(b)-- endlocalbla= {
foo=5,
bla="asd",
}
localfoo= {
tan=4
}
localzubi= {
man=0,
bla="oho"
}
localending= {
klos="hallo"
}
typeCombinedLight= {
foo: number,
bla: string,
-- tan: number,
}
localblaPartial=PartialMapping.new(bla)
--- Caveat 1: Using operator overloading somehow not possible. Type checker doesn't --- understand that the type has a + operator if we define type PartialMapping<A> as PartialMappingMetatable<A> & A (an intersection).--- Without the intersection, it will not transport the fields of A. I think what we need is a generic metatable.localresult: CombinedLight=blaPartial+foo
The text was updated successfully, but these errors were encountered:
The Luau type checking introduced in #908 works great already but there are a few things that could be improved. However, I think they require Luau improvements.
Here's the file in which I did a bunch of type checking experiments. It contains comments which things are still lacking.
The text was updated successfully, but these errors were encountered: