mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-13 05:20:38 +00:00
d21b6fdb93
# What's Changed * Fix a case where the stack wasn't completely cleaned up where `debug.info` errored when passed `"f"` option and a thread. * Fix a case of uninitialized field in `luaF_newproto`. ### New Type Solver * When a local is captured in a function, don't add a new entry to the `DfgScope::bindings` if the capture occurs within a loop. * Fix a poor performance characteristic during unification by not trying to simplify an intersection. * Fix a case of multiple constraints mutating the same blocked type causing incorrect inferences. * Fix a case of assertion failure when overload resolution encounters a return typepack mismatch. * When refining a property of the top `table` type, we no longer signal an unknown property error. * Fix a misuse of free types when trying to infer the type of a subscript expression. * Fix a case of assertion failure when trying to resolve an overload from `never`. ### Native Code Generation * Fix dead store optimization issues caused by partial stores. --- ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@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> --------- Co-authored-by: Aaron Weiss <aaronweiss@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>
187 lines
4.2 KiB
C++
187 lines
4.2 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/Common.h"
|
|
#include "Luau/DenseHash.h"
|
|
|
|
LUAU_FASTFLAG(LuauFixSetIter)
|
|
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
|
|
|
|
namespace Luau
|
|
{
|
|
|
|
template<typename T>
|
|
using SetHashDefault = std::conditional_t<std::is_pointer_v<T>, DenseHashPointer, std::hash<T>>;
|
|
|
|
// This is an implementation of `unordered_set` using `DenseHashMap<T, bool>` to support erasure.
|
|
// This lets us work around `DenseHashSet` limitations and get a more traditional set interface.
|
|
template<typename T, typename Hash = SetHashDefault<T>>
|
|
class Set
|
|
{
|
|
private:
|
|
using Impl = DenseHashMap<T, bool, Hash>;
|
|
Impl mapping;
|
|
size_t entryCount = 0;
|
|
|
|
public:
|
|
class const_iterator;
|
|
using iterator = const_iterator;
|
|
|
|
Set(const T& empty_key)
|
|
: mapping{empty_key}
|
|
{
|
|
}
|
|
|
|
bool insert(const T& element)
|
|
{
|
|
bool& entry = mapping[element];
|
|
bool fresh = !entry;
|
|
|
|
if (fresh)
|
|
{
|
|
entry = true;
|
|
entryCount++;
|
|
}
|
|
|
|
return fresh;
|
|
}
|
|
|
|
template<class Iterator>
|
|
void insert(Iterator begin, Iterator end)
|
|
{
|
|
for (Iterator it = begin; it != end; ++it)
|
|
insert(*it);
|
|
}
|
|
|
|
void erase(const T& element)
|
|
{
|
|
bool& entry = mapping[element];
|
|
|
|
if (entry)
|
|
{
|
|
entry = false;
|
|
entryCount--;
|
|
}
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
mapping.clear();
|
|
entryCount = 0;
|
|
}
|
|
|
|
size_t size() const
|
|
{
|
|
return entryCount;
|
|
}
|
|
|
|
bool empty() const
|
|
{
|
|
return entryCount == 0;
|
|
}
|
|
|
|
size_t count(const T& element) const
|
|
{
|
|
const bool* entry = mapping.find(element);
|
|
return (entry && *entry) ? 1 : 0;
|
|
}
|
|
|
|
bool contains(const T& element) const
|
|
{
|
|
return count(element) != 0;
|
|
}
|
|
|
|
const_iterator begin() const
|
|
{
|
|
return const_iterator(mapping.begin(), mapping.end());
|
|
}
|
|
|
|
const_iterator end() const
|
|
{
|
|
return const_iterator(mapping.end(), mapping.end());
|
|
}
|
|
|
|
bool operator==(const Set<T>& there) const
|
|
{
|
|
// if the sets are unequal sizes, then they cannot possibly be equal.
|
|
if (size() != there.size())
|
|
return false;
|
|
|
|
// otherwise, we'll need to check that every element we have here is in `there`.
|
|
for (auto [elem, present] : mapping)
|
|
{
|
|
// if it's not, we'll return `false`
|
|
if (present && there.contains(elem))
|
|
return false;
|
|
}
|
|
|
|
// otherwise, we've proven the two equal!
|
|
return true;
|
|
}
|
|
|
|
class const_iterator
|
|
{
|
|
public:
|
|
using value_type = T;
|
|
using reference = T&;
|
|
using pointer = T*;
|
|
using difference_type = ptrdiff_t;
|
|
using iterator_category = std::forward_iterator_tag;
|
|
|
|
const_iterator(typename Impl::const_iterator impl_, typename Impl::const_iterator end_)
|
|
: impl(impl_)
|
|
, end(end_)
|
|
{
|
|
if (FFlag::LuauFixSetIter || FFlag::DebugLuauDeferredConstraintResolution)
|
|
{
|
|
while (impl != end && impl->second == false)
|
|
++impl;
|
|
}
|
|
}
|
|
|
|
const T& operator*() const
|
|
{
|
|
return impl->first;
|
|
}
|
|
|
|
const T* operator->() const
|
|
{
|
|
return &impl->first;
|
|
}
|
|
|
|
bool operator==(const const_iterator& other) const
|
|
{
|
|
return impl == other.impl;
|
|
}
|
|
|
|
bool operator!=(const const_iterator& other) const
|
|
{
|
|
return impl != other.impl;
|
|
}
|
|
|
|
|
|
const_iterator& operator++()
|
|
{
|
|
do
|
|
{
|
|
impl++;
|
|
} while (impl != end && impl->second == false);
|
|
// keep iterating past pairs where the value is `false`
|
|
|
|
return *this;
|
|
}
|
|
|
|
const_iterator operator++(int)
|
|
{
|
|
const_iterator res = *this;
|
|
++*this;
|
|
return res;
|
|
}
|
|
|
|
private:
|
|
typename Impl::const_iterator impl;
|
|
typename Impl::const_iterator end;
|
|
};
|
|
};
|
|
|
|
} // namespace Luau
|