From 506d9714218c10b4b8b0d18b2224c47fd9867983 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Thu, 7 Jul 2022 18:22:39 -0700
Subject: [PATCH 1/4] Sync to upstream/release/535 (#584)

---
 Analysis/include/Luau/AstQuery.h            |   1 +
 Analysis/include/Luau/TypeInfer.h           |  24 +-
 Analysis/include/Luau/TypePack.h            |   1 +
 Analysis/include/Luau/TypeVar.h             | 157 ++++++--
 Analysis/include/Luau/VisitTypeVar.h        |   8 +
 Analysis/src/AstQuery.cpp                   | 107 +++++-
 Analysis/src/Autocomplete.cpp               | 201 +++-------
 Analysis/src/BuiltinDefinitions.cpp         |  43 ++-
 Analysis/src/Clone.cpp                      |  12 +
 Analysis/src/EmbeddedBuiltinDefinitions.cpp |   9 +-
 Analysis/src/Normalize.cpp                  |  38 +-
 Analysis/src/Substitution.cpp               |  10 +-
 Analysis/src/ToString.cpp                   |  17 +-
 Analysis/src/TxnLog.cpp                     |  59 +--
 Analysis/src/TypeAttach.cpp                 |   8 +
 Analysis/src/TypeInfer.cpp                  | 393 ++++++++++++++++----
 Analysis/src/TypePack.cpp                   |  51 ++-
 Analysis/src/TypeUtils.cpp                  |   2 +-
 Analysis/src/TypeVar.cpp                    | 269 +++++++++-----
 Analysis/src/Unifier.cpp                    |  66 ++--
 Ast/src/Parser.cpp                          |  17 +-
 CodeGen/include/Luau/AssemblyBuilderX64.h   |   3 +
 CodeGen/src/AssemblyBuilderX64.cpp          |  23 ++
 Sources.cmake                               |   8 +-
 VM/src/ltable.cpp                           |   8 +-
 VM/src/lvmexecute.cpp                       |  66 ++--
 bench/bench.py                              |  14 +-
 bench/other/regex.lua                       |   2 +-
 tests/AssemblyBuilderX64.test.cpp           |  27 ++
 tests/AstQuery.test.cpp                     |  33 ++
 tests/Fixture.h                             |   1 +
 tests/Module.test.cpp                       |   2 -
 tests/Normalize.test.cpp                    |  42 ++-
 tests/Parser.test.cpp                       |   1 -
 tests/ToString.test.cpp                     |   2 +-
 tests/TypeInfer.anyerror.test.cpp           |   8 +-
 tests/TypeInfer.builtins.test.cpp           | 143 ++++++-
 tests/TypeInfer.functions.test.cpp          |  54 ++-
 tests/TypeInfer.generics.test.cpp           |  39 +-
 tests/TypeInfer.loops.test.cpp              |   2 +-
 tests/TypeInfer.modules.test.cpp            |  45 ++-
 tests/TypeInfer.operators.test.cpp          |  22 ++
 tests/TypeInfer.primitives.test.cpp         |   2 +-
 tests/TypeInfer.provisional.test.cpp        |  13 +-
 tests/TypeInfer.refinements.test.cpp        |  45 ++-
 tests/TypeInfer.tables.test.cpp             |  14 +
 tests/TypeInfer.test.cpp                    |  10 +-
 tests/TypeInfer.tryUnify.test.cpp           |   4 +-
 tests/TypeInfer.unionTypes.test.cpp         |   2 +-
 tests/TypeInfer.unknownnever.test.cpp       | 280 ++++++++++++++
 tests/TypePack.test.cpp                     |   2 -
 tests/TypeVar.test.cpp                      |   2 -
 tests/conformance/vector.lua                |  16 +
 tools/natvis/VM.natvis                      |  32 +-
 54 files changed, 1867 insertions(+), 593 deletions(-)
 create mode 100644 tests/TypeInfer.unknownnever.test.cpp

diff --git a/Analysis/include/Luau/AstQuery.h b/Analysis/include/Luau/AstQuery.h
index dfe373a5..950a19da 100644
--- a/Analysis/include/Luau/AstQuery.h
+++ b/Analysis/include/Luau/AstQuery.h
@@ -63,6 +63,7 @@ private:
     AstLocal* local = nullptr;
 };
 
+std::vector<AstNode*> findAncestryAtPositionForAutocomplete(const SourceModule& source, Position pos);
 std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos);
 AstNode* findNodeAtPosition(const SourceModule& source, Position pos);
 AstExpr* findExprAtPosition(const SourceModule& source, Position pos);
diff --git a/Analysis/include/Luau/TypeInfer.h b/Analysis/include/Luau/TypeInfer.h
index dac2902c..3fb710bb 100644
--- a/Analysis/include/Luau/TypeInfer.h
+++ b/Analysis/include/Luau/TypeInfer.h
@@ -153,7 +153,7 @@ struct TypeChecker
         const ScopePtr& scope, const AstExprBinary& expr, TypeId lhsType, TypeId rhsType, const PredicateVec& predicates = {});
     TypeId checkBinaryOperation(
         const ScopePtr& scope, const AstExprBinary& expr, TypeId lhsType, TypeId rhsType, const PredicateVec& predicates = {});
-    WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprBinary& expr);
+    WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprBinary& expr, std::optional<TypeId> expectedType = std::nullopt);
     WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprTypeAssertion& expr);
     WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprError& expr);
     WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprIfElse& expr, std::optional<TypeId> expectedType = std::nullopt);
@@ -180,8 +180,12 @@ struct TypeChecker
         const ScopePtr& scope, Unifier& state, TypePackId paramPack, TypePackId argPack, const std::vector<Location>& argLocations);
 
     WithPredicate<TypePackId> checkExprPack(const ScopePtr& scope, const AstExpr& expr);
-    WithPredicate<TypePackId> checkExprPack(const ScopePtr& scope, const AstExprCall& expr);
+
+    WithPredicate<TypePackId> checkExprPackHelper(const ScopePtr& scope, const AstExpr& expr);
+    WithPredicate<TypePackId> checkExprPackHelper(const ScopePtr& scope, const AstExprCall& expr);
+
     std::vector<std::optional<TypeId>> getExpectedTypesForCall(const std::vector<TypeId>& overloads, size_t argumentCount, bool selfCall);
+
     std::optional<WithPredicate<TypePackId>> checkCallOverload(const ScopePtr& scope, const AstExprCall& expr, TypeId fn, TypePackId retPack,
         TypePackId argPack, TypePack* args, const std::vector<Location>* argLocations, const WithPredicate<TypePackId>& argListResult,
         std::vector<TypeId>& overloadsThatMatchArgCount, std::vector<TypeId>& overloadsThatDont, std::vector<OverloadErrorEntry>& errors);
@@ -236,10 +240,11 @@ struct TypeChecker
 
     void unifyLowerBound(TypePackId subTy, TypePackId superTy, TypeLevel demotedLevel, const Location& location);
 
-    std::optional<TypeId> findMetatableEntry(TypeId type, std::string entry, const Location& location);
-    std::optional<TypeId> findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location);
+    std::optional<TypeId> findMetatableEntry(TypeId type, std::string entry, const Location& location, bool addErrors);
+    std::optional<TypeId> findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location, bool addErrors);
 
     std::optional<TypeId> getIndexTypeFromType(const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors);
+    std::optional<TypeId> getIndexTypeFromTypeImpl(const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors);
 
     // Reduces the union to its simplest possible shape.
     // (A | B) | B | C yields A | B | C
@@ -316,11 +321,12 @@ private:
 
     TypeIdPredicate mkTruthyPredicate(bool sense);
 
-    // Returns nullopt if the predicate filters down the TypeId to 0 options.
-    std::optional<TypeId> filterMap(TypeId type, TypeIdPredicate predicate);
+    // TODO: Return TypeId only.
+    std::optional<TypeId> filterMapImpl(TypeId type, TypeIdPredicate predicate);
+    std::pair<std::optional<TypeId>, bool> filterMap(TypeId type, TypeIdPredicate predicate);
 
 public:
-    std::optional<TypeId> pickTypesFromSense(TypeId type, bool sense);
+    std::pair<std::optional<TypeId>, bool> pickTypesFromSense(TypeId type, bool sense);
 
 private:
     TypeId unionOfTypes(TypeId a, TypeId b, const Location& location, bool unifyFreeTypes = true);
@@ -413,8 +419,12 @@ public:
     const TypeId booleanType;
     const TypeId threadType;
     const TypeId anyType;
+    const TypeId unknownType;
+    const TypeId neverType;
 
     const TypePackId anyTypePack;
+    const TypePackId neverTypePack;
+    const TypePackId uninhabitableTypePack;
 
 private:
     int checkRecursionCount = 0;
diff --git a/Analysis/include/Luau/TypePack.h b/Analysis/include/Luau/TypePack.h
index c1de242f..b17003b1 100644
--- a/Analysis/include/Luau/TypePack.h
+++ b/Analysis/include/Luau/TypePack.h
@@ -173,5 +173,6 @@ std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp,
 bool isVariadic(TypePackId tp);
 bool isVariadic(TypePackId tp, const TxnLog& log);
 
+bool containsNever(TypePackId tp);
 
 } // namespace Luau
diff --git a/Analysis/include/Luau/TypeVar.h b/Analysis/include/Luau/TypeVar.h
index 6ad6b927..fb6093df 100644
--- a/Analysis/include/Luau/TypeVar.h
+++ b/Analysis/include/Luau/TypeVar.h
@@ -460,10 +460,18 @@ struct LazyTypeVar
     std::function<TypeId()> thunk;
 };
 
+struct UnknownTypeVar
+{
+};
+
+struct NeverTypeVar
+{
+};
+
 using ErrorTypeVar = Unifiable::Error;
 
 using TypeVariant = Unifiable::Variant<TypeId, PrimitiveTypeVar, ConstrainedTypeVar, BlockedTypeVar, SingletonTypeVar, FunctionTypeVar, TableTypeVar,
-    MetatableTypeVar, ClassTypeVar, AnyTypeVar, UnionTypeVar, IntersectionTypeVar, LazyTypeVar>;
+    MetatableTypeVar, ClassTypeVar, AnyTypeVar, UnionTypeVar, IntersectionTypeVar, LazyTypeVar, UnknownTypeVar, NeverTypeVar>;
 
 struct TypeVar final
 {
@@ -575,8 +583,12 @@ struct SingletonTypes
     const TypeId trueType;
     const TypeId falseType;
     const TypeId anyType;
+    const TypeId unknownType;
+    const TypeId neverType;
 
     const TypePackId anyTypePack;
+    const TypePackId neverTypePack;
+    const TypePackId uninhabitableTypePack;
 
     SingletonTypes();
     ~SingletonTypes();
@@ -632,12 +644,30 @@ T* getMutable(TypeId tv)
     return get_if<T>(&asMutable(tv)->ty);
 }
 
-/* Traverses the UnionTypeVar yielding each TypeId.
- * If the iterator encounters a nested UnionTypeVar, it will instead yield each TypeId within.
- *
- * Beware: the iterator does not currently filter for unique TypeIds. This may change in the future.
+const std::vector<TypeId>& getTypes(const UnionTypeVar* utv);
+const std::vector<TypeId>& getTypes(const IntersectionTypeVar* itv);
+const std::vector<TypeId>& getTypes(const ConstrainedTypeVar* ctv);
+
+template<typename T>
+struct TypeIterator;
+
+using UnionTypeVarIterator = TypeIterator<UnionTypeVar>;
+UnionTypeVarIterator begin(const UnionTypeVar* utv);
+UnionTypeVarIterator end(const UnionTypeVar* utv);
+
+using IntersectionTypeVarIterator = TypeIterator<IntersectionTypeVar>;
+IntersectionTypeVarIterator begin(const IntersectionTypeVar* itv);
+IntersectionTypeVarIterator end(const IntersectionTypeVar* itv);
+
+using ConstrainedTypeVarIterator = TypeIterator<ConstrainedTypeVar>;
+ConstrainedTypeVarIterator begin(const ConstrainedTypeVar* ctv);
+ConstrainedTypeVarIterator end(const ConstrainedTypeVar* ctv);
+
+/* Traverses the type T yielding each TypeId.
+ * If the iterator encounters a nested type T, it will instead yield each TypeId within.
  */
-struct UnionTypeVarIterator
+template<typename T>
+struct TypeIterator
 {
     using value_type = Luau::TypeId;
     using pointer = value_type*;
@@ -645,33 +675,116 @@ struct UnionTypeVarIterator
     using difference_type = size_t;
     using iterator_category = std::input_iterator_tag;
 
-    explicit UnionTypeVarIterator(const UnionTypeVar* utv);
+    explicit TypeIterator(const T* t)
+    {
+        LUAU_ASSERT(t);
 
-    UnionTypeVarIterator& operator++();
-    UnionTypeVarIterator operator++(int);
-    bool operator!=(const UnionTypeVarIterator& rhs);
-    bool operator==(const UnionTypeVarIterator& rhs);
+        const std::vector<TypeId>& types = getTypes(t);
+        if (!types.empty())
+            stack.push_front({t, 0});
 
-    const TypeId& operator*();
+        seen.insert(t);
+    }
 
-    friend UnionTypeVarIterator end(const UnionTypeVar* utv);
+    TypeIterator<T>& operator++()
+    {
+        advance();
+        descend();
+        return *this;
+    }
+
+    TypeIterator<T> operator++(int)
+    {
+        TypeIterator<T> copy = *this;
+        ++copy;
+        return copy;
+    }
+
+    bool operator==(const TypeIterator<T>& rhs) const
+    {
+        if (!stack.empty() && !rhs.stack.empty())
+            return stack.front() == rhs.stack.front();
+
+        return stack.empty() && rhs.stack.empty();
+    }
+
+    bool operator!=(const TypeIterator<T>& rhs) const
+    {
+        return !(*this == rhs);
+    }
+
+    const TypeId& operator*()
+    {
+        LUAU_ASSERT(!stack.empty());
+
+        descend();
+
+        auto [t, currentIndex] = stack.front();
+        LUAU_ASSERT(t);
+        const std::vector<TypeId>& types = getTypes(t);
+        LUAU_ASSERT(currentIndex < types.size());
+
+        const TypeId& ty = types[currentIndex];
+        LUAU_ASSERT(!get<T>(follow(ty)));
+        return ty;
+    }
+
+    // Normally, we'd have `begin` and `end` be a template but there's too much trouble
+    // with templates portability in this area, so not worth it. Thanks MSVC.
+    friend UnionTypeVarIterator end(const UnionTypeVar*);
+    friend IntersectionTypeVarIterator end(const IntersectionTypeVar*);
+    friend ConstrainedTypeVarIterator end(const ConstrainedTypeVar*);
 
 private:
-    UnionTypeVarIterator() = default;
+    TypeIterator() = default;
 
-    // (UnionTypeVar* utv, size_t currentIndex)
-    using SavedIterInfo = std::pair<const UnionTypeVar*, size_t>;
+    // (T* t, size_t currentIndex)
+    using SavedIterInfo = std::pair<const T*, size_t>;
 
     std::deque<SavedIterInfo> stack;
-    std::unordered_set<const UnionTypeVar*> seen; // Only needed to protect the iterator from hanging the thread.
+    std::unordered_set<const T*> seen; // Only needed to protect the iterator from hanging the thread.
 
-    void advance();
-    void descend();
+    void advance()
+    {
+        while (!stack.empty())
+        {
+            auto& [t, currentIndex] = stack.front();
+            ++currentIndex;
+
+            const std::vector<TypeId>& types = getTypes(t);
+            if (currentIndex >= types.size())
+                stack.pop_front();
+            else
+                break;
+        }
+    }
+
+    void descend()
+    {
+        while (!stack.empty())
+        {
+            auto [current, currentIndex] = stack.front();
+            const std::vector<TypeId>& types = getTypes(current);
+            if (auto inner = get<T>(follow(types[currentIndex])))
+            {
+                // If we're about to descend into a cyclic type, we should skip over this.
+                // Ideally this should never happen, but alas it does from time to time. :(
+                if (seen.find(inner) != seen.end())
+                    advance();
+                else
+                {
+                    seen.insert(inner);
+                    stack.push_front({inner, 0});
+                }
+
+                continue;
+            }
+
+            break;
+        }
+    }
 };
 
-UnionTypeVarIterator begin(const UnionTypeVar* utv);
-UnionTypeVarIterator end(const UnionTypeVar* utv);
-
 using TypeIdPredicate = std::function<std::optional<TypeId>(TypeId)>;
 std::vector<TypeId> filterMap(TypeId type, TypeIdPredicate predicate);
 
diff --git a/Analysis/include/Luau/VisitTypeVar.h b/Analysis/include/Luau/VisitTypeVar.h
index 5fd43f0b..ab4a397d 100644
--- a/Analysis/include/Luau/VisitTypeVar.h
+++ b/Analysis/include/Luau/VisitTypeVar.h
@@ -129,6 +129,14 @@ struct GenericTypeVarVisitor
     {
         return visit(ty);
     }
+    virtual bool visit(TypeId ty, const UnknownTypeVar& atv)
+    {
+        return visit(ty);
+    }
+    virtual bool visit(TypeId ty, const NeverTypeVar& atv)
+    {
+        return visit(ty);
+    }
     virtual bool visit(TypeId ty, const UnionTypeVar& utv)
     {
         return visit(ty);
diff --git a/Analysis/src/AstQuery.cpp b/Analysis/src/AstQuery.cpp
index 0522b1fa..1124c29e 100644
--- a/Analysis/src/AstQuery.cpp
+++ b/Analysis/src/AstQuery.cpp
@@ -17,6 +17,104 @@ namespace Luau
 namespace
 {
 
+
+struct AutocompleteNodeFinder : public AstVisitor
+{
+    const Position pos;
+    std::vector<AstNode*> ancestry;
+
+    explicit AutocompleteNodeFinder(Position pos, AstNode* root)
+        : pos(pos)
+    {
+    }
+
+    bool visit(AstExpr* expr) override
+    {
+        if (expr->location.begin < pos && pos <= expr->location.end)
+        {
+            ancestry.push_back(expr);
+            return true;
+        }
+        return false;
+    }
+
+    bool visit(AstStat* stat) override
+    {
+        if (stat->location.begin < pos && pos <= stat->location.end)
+        {
+            ancestry.push_back(stat);
+            return true;
+        }
+        return false;
+    }
+
+    bool visit(AstType* type) override
+    {
+        if (type->location.begin < pos && pos <= type->location.end)
+        {
+            ancestry.push_back(type);
+            return true;
+        }
+        return false;
+    }
+
+    bool visit(AstTypeError* type) override
+    {
+        // For a missing type, match the whole range including the start position
+        if (type->isMissing && type->location.containsClosed(pos))
+        {
+            ancestry.push_back(type);
+            return true;
+        }
+        return false;
+    }
+
+    bool visit(class AstTypePack* typePack) override
+    {
+        return true;
+    }
+
+    bool visit(AstStatBlock* block) override
+    {
+        // If ancestry is empty, we are inspecting the root of the AST.  Its extent is considered to be infinite.
+        if (ancestry.empty())
+        {
+            ancestry.push_back(block);
+            return true;
+        }
+
+        // AstExprIndexName nodes are nested outside-in, so we want the outermost node in the case of nested nodes.
+        // ex foo.bar.baz is represented in the AST as IndexName{ IndexName {foo, bar}, baz}
+        if (!ancestry.empty() && ancestry.back()->is<AstExprIndexName>())
+            return false;
+
+        // Type annotation error might intersect the block statement when the function header is being written,
+        // annotation takes priority
+        if (!ancestry.empty() && ancestry.back()->is<AstTypeError>())
+            return false;
+
+        // If the cursor is at the end of an expression or type and simultaneously at the beginning of a block,
+        // the expression or type wins out.
+        // The exception to this is if we are in a block under an AstExprFunction.  In this case, we consider the position to
+        // be within the block.
+        if (block->location.begin == pos && !ancestry.empty())
+        {
+            if (ancestry.back()->asExpr() && !ancestry.back()->is<AstExprFunction>())
+                return false;
+
+            if (ancestry.back()->asType())
+                return false;
+        }
+
+        if (block->location.begin <= pos && pos <= block->location.end)
+        {
+            ancestry.push_back(block);
+            return true;
+        }
+        return false;
+    }
+};
+
 struct FindNode : public AstVisitor
 {
     const Position pos;
@@ -102,6 +200,13 @@ struct FindFullAncestry final : public AstVisitor
 
 } // namespace
 
+std::vector<AstNode*> findAncestryAtPositionForAutocomplete(const SourceModule& source, Position pos)
+{
+    AutocompleteNodeFinder finder{pos, source.root};
+    source.root->visit(&finder);
+    return finder.ancestry;
+}
+
 std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos)
 {
     const Position end = source.root->location.end;
@@ -110,7 +215,7 @@ std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Posi
 
     FindFullAncestry finder(pos, end);
     source.root->visit(&finder);
-    return std::move(finder.nodes);
+    return finder.nodes;
 }
 
 AstNode* findNodeAtPosition(const SourceModule& source, Position pos)
diff --git a/Analysis/src/Autocomplete.cpp b/Analysis/src/Autocomplete.cpp
index 8a63901f..cc54d499 100644
--- a/Analysis/src/Autocomplete.cpp
+++ b/Analysis/src/Autocomplete.cpp
@@ -21,102 +21,6 @@ static const std::unordered_set<std::string> kStatementStartingKeywords = {
 namespace Luau
 {
 
-struct NodeFinder : public AstVisitor
-{
-    const Position pos;
-    std::vector<AstNode*> ancestry;
-
-    explicit NodeFinder(Position pos, AstNode* root)
-        : pos(pos)
-    {
-    }
-
-    bool visit(AstExpr* expr) override
-    {
-        if (expr->location.begin < pos && pos <= expr->location.end)
-        {
-            ancestry.push_back(expr);
-            return true;
-        }
-        return false;
-    }
-
-    bool visit(AstStat* stat) override
-    {
-        if (stat->location.begin < pos && pos <= stat->location.end)
-        {
-            ancestry.push_back(stat);
-            return true;
-        }
-        return false;
-    }
-
-    bool visit(AstType* type) override
-    {
-        if (type->location.begin < pos && pos <= type->location.end)
-        {
-            ancestry.push_back(type);
-            return true;
-        }
-        return false;
-    }
-
-    bool visit(AstTypeError* type) override
-    {
-        // For a missing type, match the whole range including the start position
-        if (type->isMissing && type->location.containsClosed(pos))
-        {
-            ancestry.push_back(type);
-            return true;
-        }
-        return false;
-    }
-
-    bool visit(class AstTypePack* typePack) override
-    {
-        return true;
-    }
-
-    bool visit(AstStatBlock* block) override
-    {
-        // If ancestry is empty, we are inspecting the root of the AST.  Its extent is considered to be infinite.
-        if (ancestry.empty())
-        {
-            ancestry.push_back(block);
-            return true;
-        }
-
-        // AstExprIndexName nodes are nested outside-in, so we want the outermost node in the case of nested nodes.
-        // ex foo.bar.baz is represented in the AST as IndexName{ IndexName {foo, bar}, baz}
-        if (!ancestry.empty() && ancestry.back()->is<AstExprIndexName>())
-            return false;
-
-        // Type annotation error might intersect the block statement when the function header is being written,
-        // annotation takes priority
-        if (!ancestry.empty() && ancestry.back()->is<AstTypeError>())
-            return false;
-
-        // If the cursor is at the end of an expression or type and simultaneously at the beginning of a block,
-        // the expression or type wins out.
-        // The exception to this is if we are in a block under an AstExprFunction.  In this case, we consider the position to
-        // be within the block.
-        if (block->location.begin == pos && !ancestry.empty())
-        {
-            if (ancestry.back()->asExpr() && !ancestry.back()->is<AstExprFunction>())
-                return false;
-
-            if (ancestry.back()->asType())
-                return false;
-        }
-
-        if (block->location.begin <= pos && pos <= block->location.end)
-        {
-            ancestry.push_back(block);
-            return true;
-        }
-        return false;
-    }
-};
 
 static bool alreadyHasParens(const std::vector<AstNode*>& nodes)
 {
@@ -905,7 +809,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
     }
 
     AstNode* parent = nullptr;
-    AstType* topType = nullptr;
+    AstType* topType = nullptr; // TODO: rename?
 
     for (auto it = ancestry.rbegin(), e = ancestry.rend(); it != e; ++it)
     {
@@ -1477,21 +1381,20 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
     if (isWithinComment(sourceModule, position))
         return {};
 
-    NodeFinder finder{position, sourceModule.root};
-    sourceModule.root->visit(&finder);
-    LUAU_ASSERT(!finder.ancestry.empty());
-    AstNode* node = finder.ancestry.back();
+    std::vector<AstNode*> ancestry = findAncestryAtPositionForAutocomplete(sourceModule, position);
+    LUAU_ASSERT(!ancestry.empty());
+    AstNode* node = ancestry.back();
 
     AstExprConstantNil dummy{Location{}};
-    AstNode* parent = finder.ancestry.size() >= 2 ? finder.ancestry.rbegin()[1] : &dummy;
+    AstNode* parent = ancestry.size() >= 2 ? ancestry.rbegin()[1] : &dummy;
 
     // If we are inside a body of a function that doesn't have a completed argument list, ignore the body node
     if (auto exprFunction = parent->as<AstExprFunction>(); exprFunction && !exprFunction->argLocation && node == exprFunction->body)
     {
-        finder.ancestry.pop_back();
+        ancestry.pop_back();
 
-        node = finder.ancestry.back();
-        parent = finder.ancestry.size() >= 2 ? finder.ancestry.rbegin()[1] : &dummy;
+        node = ancestry.back();
+        parent = ancestry.size() >= 2 ? ancestry.rbegin()[1] : &dummy;
     }
 
     if (auto indexName = node->as<AstExprIndexName>())
@@ -1504,47 +1407,47 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
         PropIndexType indexType = indexName->op == ':' ? PropIndexType::Colon : PropIndexType::Point;
 
         if (!FFlag::LuauSelfCallAutocompleteFix2 && isString(ty))
-            return {autocompleteProps(*module, typeArena, typeChecker.globalScope->bindings[AstName{"string"}].typeId, indexType, finder.ancestry),
-                finder.ancestry};
+            return {autocompleteProps(*module, typeArena, typeChecker.globalScope->bindings[AstName{"string"}].typeId, indexType, ancestry),
+                ancestry};
         else
-            return {autocompleteProps(*module, typeArena, ty, indexType, finder.ancestry), finder.ancestry};
+            return {autocompleteProps(*module, typeArena, ty, indexType, ancestry), ancestry};
     }
     else if (auto typeReference = node->as<AstTypeReference>())
     {
         if (typeReference->prefix)
-            return {autocompleteModuleTypes(*module, position, typeReference->prefix->value), finder.ancestry};
+            return {autocompleteModuleTypes(*module, position, typeReference->prefix->value), ancestry};
         else
-            return {autocompleteTypeNames(*module, position, finder.ancestry), finder.ancestry};
+            return {autocompleteTypeNames(*module, position, ancestry), ancestry};
     }
     else if (node->is<AstTypeError>())
     {
-        return {autocompleteTypeNames(*module, position, finder.ancestry), finder.ancestry};
+        return {autocompleteTypeNames(*module, position, ancestry), ancestry};
     }
     else if (AstStatLocal* statLocal = node->as<AstStatLocal>())
     {
         if (statLocal->vars.size == 1 && (!statLocal->equalsSignLocation || position < statLocal->equalsSignLocation->begin))
-            return {{{"function", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+            return {{{"function", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
         else if (statLocal->equalsSignLocation && position >= statLocal->equalsSignLocation->end)
-            return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position), finder.ancestry};
+            return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position), ancestry};
         else
             return {};
     }
 
-    else if (AstStatFor* statFor = extractStat<AstStatFor>(finder.ancestry))
+    else if (AstStatFor* statFor = extractStat<AstStatFor>(ancestry))
     {
         if (!statFor->hasDo || position < statFor->doLocation.begin)
         {
             if (!statFor->from->is<AstExprError>() && !statFor->to->is<AstExprError>() && (!statFor->step || !statFor->step->is<AstExprError>()))
-                return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+                return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
 
             if (statFor->from->location.containsClosed(position) || statFor->to->location.containsClosed(position) ||
                 (statFor->step && statFor->step->location.containsClosed(position)))
-                return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position), finder.ancestry};
+                return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position), ancestry};
 
             return {};
         }
 
-        return {autocompleteStatement(sourceModule, *module, finder.ancestry, position), finder.ancestry};
+        return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry};
     }
 
     else if (AstStatForIn* statForIn = parent->as<AstStatForIn>(); statForIn && (node->is<AstStatBlock>() || isIdentifier(node)))
@@ -1560,7 +1463,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
                 return {};
             }
 
-            return {{{"in", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+            return {{{"in", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
         }
 
         if (!statForIn->hasDo || position <= statForIn->doLocation.begin)
@@ -1569,58 +1472,58 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
             AstExpr* lastExpr = statForIn->values.data[statForIn->values.size - 1];
 
             if (lastExpr->location.containsClosed(position))
-                return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position), finder.ancestry};
+                return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position), ancestry};
 
             if (position > lastExpr->location.end)
-                return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+                return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
 
             return {}; // Not sure what this means
         }
     }
-    else if (AstStatForIn* statForIn = extractStat<AstStatForIn>(finder.ancestry))
+    else if (AstStatForIn* statForIn = extractStat<AstStatForIn>(ancestry))
     {
         // The AST looks a bit differently if the cursor is at a position where only the "do" keyword is allowed.
         // ex "for f in f do"
         if (!statForIn->hasDo)
-            return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+            return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
 
-        return {autocompleteStatement(sourceModule, *module, finder.ancestry, position), finder.ancestry};
+        return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry};
     }
 
     else if (AstStatWhile* statWhile = parent->as<AstStatWhile>(); node->is<AstStatBlock>() && statWhile)
     {
         if (!statWhile->hasDo && !statWhile->condition->is<AstStatError>() && position > statWhile->condition->location.end)
-            return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+            return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
 
         if (!statWhile->hasDo || position < statWhile->doLocation.begin)
-            return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position), finder.ancestry};
+            return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position), ancestry};
 
         if (statWhile->hasDo && position > statWhile->doLocation.end)
-            return {autocompleteStatement(sourceModule, *module, finder.ancestry, position), finder.ancestry};
+            return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry};
     }
 
-    else if (AstStatWhile* statWhile = extractStat<AstStatWhile>(finder.ancestry); statWhile && !statWhile->hasDo)
-        return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+    else if (AstStatWhile* statWhile = extractStat<AstStatWhile>(ancestry); statWhile && !statWhile->hasDo)
+        return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
 
     else if (AstStatIf* statIf = node->as<AstStatIf>(); statIf && !statIf->elseLocation.has_value())
     {
         return {{{"else", AutocompleteEntry{AutocompleteEntryKind::Keyword}}, {"elseif", AutocompleteEntry{AutocompleteEntryKind::Keyword}}},
-            finder.ancestry};
+            ancestry};
     }
     else if (AstStatIf* statIf = parent->as<AstStatIf>(); statIf && node->is<AstStatBlock>())
     {
         if (statIf->condition->is<AstExprError>())
-            return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position), finder.ancestry};
+            return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position), ancestry};
         else if (!statIf->thenLocation || statIf->thenLocation->containsClosed(position))
-            return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+            return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
     }
-    else if (AstStatIf* statIf = extractStat<AstStatIf>(finder.ancestry);
+    else if (AstStatIf* statIf = extractStat<AstStatIf>(ancestry);
              statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)))
-        return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
+        return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry};
     else if (AstStatRepeat* statRepeat = node->as<AstStatRepeat>(); statRepeat && statRepeat->condition->is<AstExprError>())
-        return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position), finder.ancestry};
-    else if (AstStatRepeat* statRepeat = extractStat<AstStatRepeat>(finder.ancestry); statRepeat)
-        return {autocompleteStatement(sourceModule, *module, finder.ancestry, position), finder.ancestry};
+        return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position), ancestry};
+    else if (AstStatRepeat* statRepeat = extractStat<AstStatRepeat>(ancestry); statRepeat)
+        return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry};
     else if (AstExprTable* exprTable = parent->as<AstExprTable>(); exprTable && (node->is<AstExprGlobal>() || node->is<AstExprConstantString>()))
     {
         for (const auto& [kind, key, value] : exprTable->items)
@@ -1630,7 +1533,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
             {
                 if (auto it = module->astExpectedTypes.find(exprTable))
                 {
-                    auto result = autocompleteProps(*module, typeArena, *it, PropIndexType::Key, finder.ancestry);
+                    auto result = autocompleteProps(*module, typeArena, *it, PropIndexType::Key, ancestry);
 
                     // Remove keys that are already completed
                     for (const auto& item : exprTable->items)
@@ -1644,9 +1547,9 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
 
                     // If we know for sure that a key is being written, do not offer general expression suggestions
                     if (!key)
-                        autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position, result);
+                        autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position, result);
 
-                    return {result, finder.ancestry};
+                    return {result, ancestry};
                 }
 
                 break;
@@ -1654,11 +1557,11 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
         }
     }
     else if (isIdentifier(node) && (parent->is<AstStatExpr>() || parent->is<AstStatError>()))
-        return {autocompleteStatement(sourceModule, *module, finder.ancestry, position), finder.ancestry};
+        return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry};
 
-    if (std::optional<AutocompleteEntryMap> ret = autocompleteStringParams(sourceModule, module, finder.ancestry, position, callback))
+    if (std::optional<AutocompleteEntryMap> ret = autocompleteStringParams(sourceModule, module, ancestry, position, callback))
     {
-        return {*ret, finder.ancestry};
+        return {*ret, ancestry};
     }
     else if (node->is<AstExprConstantString>())
     {
@@ -1667,14 +1570,14 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
         if (auto it = module->astExpectedTypes.find(node->asExpr()))
             autocompleteStringSingleton(*it, false, result);
 
-        if (finder.ancestry.size() >= 2)
+        if (ancestry.size() >= 2)
         {
-            if (auto idxExpr = finder.ancestry.at(finder.ancestry.size() - 2)->as<AstExprIndexExpr>())
+            if (auto idxExpr = ancestry.at(ancestry.size() - 2)->as<AstExprIndexExpr>())
             {
                 if (auto it = module->astTypes.find(idxExpr->expr))
-                    autocompleteProps(*module, typeArena, follow(*it), PropIndexType::Point, finder.ancestry, result);
+                    autocompleteProps(*module, typeArena, follow(*it), PropIndexType::Point, ancestry, result);
             }
-            else if (auto binExpr = finder.ancestry.at(finder.ancestry.size() - 2)->as<AstExprBinary>())
+            else if (auto binExpr = ancestry.at(ancestry.size() - 2)->as<AstExprBinary>())
             {
                 if (binExpr->op == AstExprBinary::CompareEq || binExpr->op == AstExprBinary::CompareNe)
                 {
@@ -1684,7 +1587,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
             }
         }
 
-        return {result, finder.ancestry};
+        return {result, ancestry};
     }
 
     if (node->is<AstExprConstantNumber>())
@@ -1693,9 +1596,9 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
     }
 
     if (node->asExpr())
-        return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position), finder.ancestry};
+        return {autocompleteExpression(sourceModule, *module, typeChecker, typeArena, ancestry, position), ancestry};
     else if (node->asStat())
-        return {autocompleteStatement(sourceModule, *module, finder.ancestry, position), finder.ancestry};
+        return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry};
 
     return {};
 }
diff --git a/Analysis/src/BuiltinDefinitions.cpp b/Analysis/src/BuiltinDefinitions.cpp
index 2f57e23c..aeba2c13 100644
--- a/Analysis/src/BuiltinDefinitions.cpp
+++ b/Analysis/src/BuiltinDefinitions.cpp
@@ -9,6 +9,7 @@
 #include <algorithm>
 
 LUAU_FASTFLAGVARIABLE(LuauSetMetaTableArgsCheck, false)
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
 
 /** FIXME: Many of these type definitions are not quite completely accurate.
  *
@@ -222,14 +223,14 @@ void registerBuiltinTypes(TypeChecker& typeChecker)
 
     addGlobalBinding(typeChecker, "getmetatable", makeFunction(arena, std::nullopt, {genericMT}, {}, {tableMetaMT}, {genericMT}), "@luau");
 
-    // setmetatable<MT>({ @metatable MT }, MT) -> { @metatable MT }
     // clang-format off
+    // setmetatable<T: {}, MT>(T, MT) -> { @metatable MT, T }
     addGlobalBinding(typeChecker, "setmetatable",
         arena.addType(
             FunctionTypeVar{
                 {genericMT},
                 {},
-                arena.addTypePack(TypePack{{tableMetaMT, genericMT}}),
+                arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}),
                 arena.addTypePack(TypePack{{tableMetaMT}})
             }
         ), "@luau"
@@ -309,6 +310,12 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
 {
     auto [paramPack, _predicates] = withPredicate;
 
+    if (FFlag::LuauUnknownAndNeverType)
+    {
+        if (size(paramPack) < 2 && finite(paramPack))
+            return std::nullopt;
+    }
+
     TypeArena& arena = typechecker.currentModule->internalTypes;
 
     std::vector<TypeId> expectedArgs = typechecker.unTypePack(scope, paramPack, 2, expr.location);
@@ -316,6 +323,12 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
     TypeId target = follow(expectedArgs[0]);
     TypeId mt = follow(expectedArgs[1]);
 
+    if (FFlag::LuauUnknownAndNeverType)
+    {
+        typechecker.tablify(target);
+        typechecker.tablify(mt);
+    }
+
     if (const auto& tab = get<TableTypeVar>(target))
     {
         if (target->persistent)
@@ -324,7 +337,8 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
         }
         else
         {
-            typechecker.tablify(mt);
+            if (!FFlag::LuauUnknownAndNeverType)
+                typechecker.tablify(mt);
 
             const TableTypeVar* mtTtv = get<TableTypeVar>(mt);
             MetatableTypeVar mtv{target, mt};
@@ -343,7 +357,10 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
 
             if (FFlag::LuauSetMetaTableArgsCheck && expr.args.size < 1)
             {
-                return WithPredicate<TypePackId>{};
+                if (FFlag::LuauUnknownAndNeverType)
+                    return std::nullopt;
+                else
+                    return WithPredicate<TypePackId>{};
             }
 
             if (!FFlag::LuauSetMetaTableArgsCheck || !expr.self)
@@ -390,11 +407,21 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionAssert(
 
     if (head.size() > 0)
     {
-        std::optional<TypeId> newhead = typechecker.pickTypesFromSense(head[0], true);
-        if (!newhead)
-            head = {typechecker.nilType};
+        auto [ty, ok] = typechecker.pickTypesFromSense(head[0], true);
+        if (FFlag::LuauUnknownAndNeverType)
+        {
+            if (get<NeverTypeVar>(*ty))
+                head = {*ty};
+            else
+                head[0] = *ty;
+        }
         else
-            head[0] = *newhead;
+        {
+            if (!ty)
+                head = {typechecker.nilType};
+            else
+                head[0] = *ty;
+        }
     }
 
     return WithPredicate<TypePackId>{arena.addTypePack(TypePack{std::move(head), tail})};
diff --git a/Analysis/src/Clone.cpp b/Analysis/src/Clone.cpp
index df4e0a6b..88c50318 100644
--- a/Analysis/src/Clone.cpp
+++ b/Analysis/src/Clone.cpp
@@ -59,6 +59,8 @@ struct TypeCloner
     void operator()(const UnionTypeVar& t);
     void operator()(const IntersectionTypeVar& t);
     void operator()(const LazyTypeVar& t);
+    void operator()(const UnknownTypeVar& t);
+    void operator()(const NeverTypeVar& t);
 };
 
 struct TypePackCloner
@@ -310,6 +312,16 @@ void TypeCloner::operator()(const LazyTypeVar& t)
     defaultClone(t);
 }
 
+void TypeCloner::operator()(const UnknownTypeVar& t)
+{
+    defaultClone(t);
+}
+
+void TypeCloner::operator()(const NeverTypeVar& t)
+{
+    defaultClone(t);
+}
+
 } // anonymous namespace
 
 TypePackId clone(TypePackId tp, TypeArena& dest, CloneState& cloneState)
diff --git a/Analysis/src/EmbeddedBuiltinDefinitions.cpp b/Analysis/src/EmbeddedBuiltinDefinitions.cpp
index 1b5275fd..f93f65dd 100644
--- a/Analysis/src/EmbeddedBuiltinDefinitions.cpp
+++ b/Analysis/src/EmbeddedBuiltinDefinitions.cpp
@@ -1,6 +1,7 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
 #include "Luau/BuiltinDefinitions.h"
 
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
 LUAU_FASTFLAG(LuauCheckLenMT)
 
 namespace Luau
@@ -116,8 +117,6 @@ declare function typeof<T>(value: T): string
 -- `assert` has a magic function attached that will give more detailed type information
 declare function assert<T>(value: T, errorMessage: string?): T
 
-declare function error<T>(message: T, level: number?)
-
 declare function tostring<T>(value: T): string
 declare function tonumber<T>(value: T, radix: number?): number?
 
@@ -204,12 +203,18 @@ declare function unpack<V>(tab: {V}, i: number?, j: number?): ...V
 
 std::string getBuiltinDefinitionSource()
 {
+
     std::string result = kBuiltinDefinitionLuaSrc;
 
     // TODO: move this into kBuiltinDefinitionLuaSrc
     if (FFlag::LuauCheckLenMT)
         result += "declare function rawlen<K, V>(obj: {[K]: V} | string): number\n";
 
+    if (FFlag::LuauUnknownAndNeverType)
+        result += "declare function error<T>(message: T, level: number?): never\n";
+    else
+        result += "declare function error<T>(message: T, level: number?)\n";
+
     return result;
 }
 
diff --git a/Analysis/src/Normalize.cpp b/Analysis/src/Normalize.cpp
index 8ce7f742..ce8f96cc 100644
--- a/Analysis/src/Normalize.cpp
+++ b/Analysis/src/Normalize.cpp
@@ -14,7 +14,7 @@ LUAU_FASTFLAGVARIABLE(DebugLuauCopyBeforeNormalizing, false)
 LUAU_FASTINTVARIABLE(LuauNormalizeIterationLimit, 1200);
 LUAU_FASTFLAGVARIABLE(LuauNormalizeCombineTableFix, false);
 LUAU_FASTFLAGVARIABLE(LuauNormalizeFlagIsConservative, false);
-LUAU_FASTFLAGVARIABLE(LuauNormalizeCombineEqFix, false);
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
 LUAU_FASTFLAG(LuauQuantifyConstrained)
 
 namespace Luau
@@ -182,7 +182,6 @@ struct Normalize final : TypeVarVisitor
     {
         if (!ty->normal)
             asMutable(ty)->normal = true;
-
         return false;
     }
 
@@ -193,6 +192,20 @@ struct Normalize final : TypeVarVisitor
         return false;
     }
 
+    bool visit(TypeId ty, const UnknownTypeVar&) override
+    {
+        if (!ty->normal)
+            asMutable(ty)->normal = true;
+        return false;
+    }
+
+    bool visit(TypeId ty, const NeverTypeVar&) override
+    {
+        if (!ty->normal)
+            asMutable(ty)->normal = true;
+        return false;
+    }
+
     bool visit(TypeId ty, const ConstrainedTypeVar& ctvRef) override
     {
         CHECK_ITERATION_LIMIT(false);
@@ -416,7 +429,13 @@ struct Normalize final : TypeVarVisitor
         std::vector<TypeId> result;
 
         for (TypeId part : options)
+        {
+            // AnyTypeVar always win the battle no matter what we do, so we're done.
+            if (FFlag::LuauUnknownAndNeverType && get<AnyTypeVar>(follow(part)))
+                return {part};
+
             combineIntoUnion(result, part);
+        }
 
         return result;
     }
@@ -427,7 +446,17 @@ struct Normalize final : TypeVarVisitor
         if (auto utv = get<UnionTypeVar>(ty))
         {
             for (TypeId t : utv)
+            {
+                // AnyTypeVar always win the battle no matter what we do, so we're done.
+                if (FFlag::LuauUnknownAndNeverType && get<AnyTypeVar>(t))
+                {
+                    result = {t};
+                    return;
+                }
+
                 combineIntoUnion(result, t);
+            }
+
             return;
         }
 
@@ -571,8 +600,7 @@ struct Normalize final : TypeVarVisitor
      */
     TypeId combine(Replacer& replacer, TypeId a, TypeId b)
     {
-        if (FFlag::LuauNormalizeCombineEqFix)
-            b = follow(b);
+        b = follow(b);
 
         if (FFlag::LuauNormalizeCombineTableFix && a == b)
             return a;
@@ -592,7 +620,7 @@ struct Normalize final : TypeVarVisitor
         }
         else if (auto ttv = getMutable<TableTypeVar>(a))
         {
-            if (FFlag::LuauNormalizeCombineTableFix && !get<TableTypeVar>(FFlag::LuauNormalizeCombineEqFix ? b : follow(b)))
+            if (FFlag::LuauNormalizeCombineTableFix && !get<TableTypeVar>(b))
                 return arena.addType(IntersectionTypeVar{{a, b}});
             combineIntoTable(replacer, ttv, b);
             return a;
diff --git a/Analysis/src/Substitution.cpp b/Analysis/src/Substitution.cpp
index 9c4ce829..7245403c 100644
--- a/Analysis/src/Substitution.cpp
+++ b/Analysis/src/Substitution.cpp
@@ -8,8 +8,10 @@
 #include <algorithm>
 #include <stdexcept>
 
+LUAU_FASTFLAGVARIABLE(LuauAnyificationMustClone, false)
 LUAU_FASTFLAG(LuauLowerBoundsCalculation)
 LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000)
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
 
 namespace Luau
 {
@@ -154,7 +156,7 @@ TarjanResult Tarjan::loop()
         if (currEdge == -1)
         {
             ++childCount;
-            if (childLimit > 0 && childLimit < childCount)
+            if (childLimit > 0 && (FFlag::LuauUnknownAndNeverType ? childLimit <= childCount : childLimit < childCount))
                 return TarjanResult::TooManyChildren;
 
             stack.push_back(index);
@@ -439,6 +441,9 @@ void Substitution::replaceChildren(TypeId ty)
     if (ignoreChildren(ty))
         return;
 
+    if (FFlag::LuauAnyificationMustClone && ty->owningArena != arena)
+        return;
+
     if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty))
     {
         ftv->argTypes = replace(ftv->argTypes);
@@ -490,6 +495,9 @@ void Substitution::replaceChildren(TypePackId tp)
     if (ignoreChildren(tp))
         return;
 
+    if (FFlag::LuauAnyificationMustClone && tp->owningArena != arena)
+        return;
+
     if (TypePack* tpp = getMutable<TypePack>(tp))
     {
         for (TypeId& tv : tpp->head)
diff --git a/Analysis/src/ToString.cpp b/Analysis/src/ToString.cpp
index 5d54d14a..6bc1d572 100644
--- a/Analysis/src/ToString.cpp
+++ b/Analysis/src/ToString.cpp
@@ -11,6 +11,7 @@
 #include <stdexcept>
 
 LUAU_FASTFLAG(LuauLowerBoundsCalculation)
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
 
 /*
  * Prefix generic typenames with gen-
@@ -841,7 +842,7 @@ struct TypeVarStringifier
     void operator()(TypeId, const ErrorTypeVar& tv)
     {
         state.result.error = true;
-        state.emit("*unknown*");
+        state.emit(FFlag::LuauUnknownAndNeverType ? "<error-type>" : "*unknown*");
     }
 
     void operator()(TypeId, const LazyTypeVar& ltv)
@@ -850,7 +851,17 @@ struct TypeVarStringifier
         state.emit("lazy?");
     }
 
-}; // namespace
+    void operator()(TypeId, const UnknownTypeVar& ttv)
+    {
+        state.emit("unknown");
+    }
+
+    void operator()(TypeId, const NeverTypeVar& ttv)
+    {
+        state.emit("never");
+    }
+
+};
 
 struct TypePackStringifier
 {
@@ -955,7 +966,7 @@ struct TypePackStringifier
     void operator()(TypePackId, const Unifiable::Error& error)
     {
         state.result.error = true;
-        state.emit("*unknown*");
+        state.emit(FFlag::LuauUnknownAndNeverType ? "<error-type>" : "*unknown*");
     }
 
     void operator()(TypePackId, const VariadicTypePack& pack)
diff --git a/Analysis/src/TxnLog.cpp b/Analysis/src/TxnLog.cpp
index 4c6d54e0..b3f60d30 100644
--- a/Analysis/src/TxnLog.cpp
+++ b/Analysis/src/TxnLog.cpp
@@ -7,7 +7,7 @@
 #include <algorithm>
 #include <stdexcept>
 
-LUAU_FASTFLAG(LuauNonCopyableTypeVarFields)
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
 
 namespace Luau
 {
@@ -81,34 +81,10 @@ void TxnLog::concat(TxnLog rhs)
 void TxnLog::commit()
 {
     for (auto& [ty, rep] : typeVarChanges)
-    {
-        if (FFlag::LuauNonCopyableTypeVarFields)
-        {
-            asMutable(ty)->reassign(rep.get()->pending);
-        }
-        else
-        {
-            TypeArena* owningArena = ty->owningArena;
-            TypeVar* mtv = asMutable(ty);
-            *mtv = rep.get()->pending;
-            mtv->owningArena = owningArena;
-        }
-    }
+        asMutable(ty)->reassign(rep.get()->pending);
 
     for (auto& [tp, rep] : typePackChanges)
-    {
-        if (FFlag::LuauNonCopyableTypeVarFields)
-        {
-            asMutable(tp)->reassign(rep.get()->pending);
-        }
-        else
-        {
-            TypeArena* owningArena = tp->owningArena;
-            TypePackVar* mpv = asMutable(tp);
-            *mpv = rep.get()->pending;
-            mpv->owningArena = owningArena;
-        }
-    }
+        asMutable(tp)->reassign(rep.get()->pending);
 
     clear();
 }
@@ -196,9 +172,7 @@ PendingType* TxnLog::queue(TypeId ty)
     if (!pending)
     {
         pending = std::make_unique<PendingType>(*ty);
-
-        if (FFlag::LuauNonCopyableTypeVarFields)
-            pending->pending.owningArena = nullptr;
+        pending->pending.owningArena = nullptr;
     }
 
     return pending.get();
@@ -214,9 +188,7 @@ PendingTypePack* TxnLog::queue(TypePackId tp)
     if (!pending)
     {
         pending = std::make_unique<PendingTypePack>(*tp);
-
-        if (FFlag::LuauNonCopyableTypeVarFields)
-            pending->pending.owningArena = nullptr;
+        pending->pending.owningArena = nullptr;
     }
 
     return pending.get();
@@ -255,24 +227,14 @@ PendingTypePack* TxnLog::pending(TypePackId tp) const
 PendingType* TxnLog::replace(TypeId ty, TypeVar replacement)
 {
     PendingType* newTy = queue(ty);
-
-    if (FFlag::LuauNonCopyableTypeVarFields)
-        newTy->pending.reassign(replacement);
-    else
-        newTy->pending = replacement;
-
+    newTy->pending.reassign(replacement);
     return newTy;
 }
 
 PendingTypePack* TxnLog::replace(TypePackId tp, TypePackVar replacement)
 {
     PendingTypePack* newTp = queue(tp);
-
-    if (FFlag::LuauNonCopyableTypeVarFields)
-        newTp->pending.reassign(replacement);
-    else
-        newTp->pending = replacement;
-
+    newTp->pending.reassign(replacement);
     return newTp;
 }
 
@@ -289,7 +251,7 @@ PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo)
 
 PendingType* TxnLog::changeLevel(TypeId ty, TypeLevel newLevel)
 {
-    LUAU_ASSERT(get<FreeTypeVar>(ty) || get<TableTypeVar>(ty) || get<FunctionTypeVar>(ty));
+    LUAU_ASSERT(get<FreeTypeVar>(ty) || get<TableTypeVar>(ty) || get<FunctionTypeVar>(ty) || get<ConstrainedTypeVar>(ty));
 
     PendingType* newTy = queue(ty);
     if (FreeTypeVar* ftv = Luau::getMutable<FreeTypeVar>(newTy))
@@ -305,6 +267,11 @@ PendingType* TxnLog::changeLevel(TypeId ty, TypeLevel newLevel)
     {
         ftv->level = newLevel;
     }
+    else if (ConstrainedTypeVar* ctv = Luau::getMutable<ConstrainedTypeVar>(newTy))
+    {
+        if (FFlag::LuauUnknownAndNeverType)
+            ctv->level = newLevel;
+    }
 
     return newTy;
 }
diff --git a/Analysis/src/TypeAttach.cpp b/Analysis/src/TypeAttach.cpp
index 6cca7127..2bc89cf6 100644
--- a/Analysis/src/TypeAttach.cpp
+++ b/Analysis/src/TypeAttach.cpp
@@ -335,6 +335,14 @@ public:
     {
         return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("<Lazy?>"));
     }
+    AstType* operator()(const UnknownTypeVar& ttv)
+    {
+        return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName{"unknown"});
+    }
+    AstType* operator()(const NeverTypeVar& ttv)
+    {
+        return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName{"never"});
+    }
 
 private:
     Allocator* allocator;
diff --git a/Analysis/src/TypeInfer.cpp b/Analysis/src/TypeInfer.cpp
index 4fafb50f..01939fda 100644
--- a/Analysis/src/TypeInfer.cpp
+++ b/Analysis/src/TypeInfer.cpp
@@ -31,6 +31,7 @@ LUAU_FASTINTVARIABLE(LuauCheckRecursionLimit, 300)
 LUAU_FASTINTVARIABLE(LuauVisitRecursionLimit, 500)
 LUAU_FASTFLAG(LuauKnowsTheDataModel3)
 LUAU_FASTFLAG(LuauAutocompleteDynamicLimits)
+LUAU_FASTFLAGVARIABLE(LuauIndexSilenceErrors, false)
 LUAU_FASTFLAGVARIABLE(LuauLowerBoundsCalculation, false)
 LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false)
 LUAU_FASTFLAGVARIABLE(LuauSelfCallAutocompleteFix2, false)
@@ -41,10 +42,12 @@ LUAU_FASTFLAGVARIABLE(LuauReturnTypeInferenceInNonstrict, false)
 LUAU_FASTFLAGVARIABLE(DebugLuauSharedSelf, false);
 LUAU_FASTFLAGVARIABLE(LuauAlwaysQuantify, false);
 LUAU_FASTFLAGVARIABLE(LuauReportErrorsOnIndexerKeyMismatch, false)
+LUAU_FASTFLAGVARIABLE(LuauUnknownAndNeverType, false)
 LUAU_FASTFLAG(LuauQuantifyConstrained)
 LUAU_FASTFLAGVARIABLE(LuauFalsyPredicateReturnsNilInstead, false)
-LUAU_FASTFLAGVARIABLE(LuauNonCopyableTypeVarFields, false)
 LUAU_FASTFLAGVARIABLE(LuauCheckLenMT, false)
+LUAU_FASTFLAGVARIABLE(LuauCheckGenericHOFTypes, false)
+LUAU_FASTFLAGVARIABLE(LuauBinaryNeedsExpectedTypesToo, false)
 
 namespace Luau
 {
@@ -258,7 +261,11 @@ TypeChecker::TypeChecker(ModuleResolver* resolver, InternalErrorReporter* iceHan
     , booleanType(getSingletonTypes().booleanType)
     , threadType(getSingletonTypes().threadType)
     , anyType(getSingletonTypes().anyType)
+    , unknownType(getSingletonTypes().unknownType)
+    , neverType(getSingletonTypes().neverType)
     , anyTypePack(getSingletonTypes().anyTypePack)
+    , neverTypePack(getSingletonTypes().neverTypePack)
+    , uninhabitableTypePack(getSingletonTypes().uninhabitableTypePack)
     , duplicateTypeAliases{{false, {}}}
 {
     globalScope = std::make_shared<Scope>(globalTypes.addTypePack(TypePackVar{FreeTypePack{TypeLevel{}}}));
@@ -269,6 +276,11 @@ TypeChecker::TypeChecker(ModuleResolver* resolver, InternalErrorReporter* iceHan
     globalScope->exportedTypeBindings["string"] = TypeFun{{}, stringType};
     globalScope->exportedTypeBindings["boolean"] = TypeFun{{}, booleanType};
     globalScope->exportedTypeBindings["thread"] = TypeFun{{}, threadType};
+    if (FFlag::LuauUnknownAndNeverType)
+    {
+        globalScope->exportedTypeBindings["unknown"] = TypeFun{{}, unknownType};
+        globalScope->exportedTypeBindings["never"] = TypeFun{{}, neverType};
+    }
 }
 
 ModulePtr TypeChecker::check(const SourceModule& module, Mode mode, std::optional<ScopePtr> environmentScope)
@@ -456,6 +468,59 @@ void TypeChecker::checkBlock(const ScopePtr& scope, const AstStatBlock& block)
     }
 }
 
+struct InplaceDemoter : TypeVarOnceVisitor
+{
+    TypeLevel newLevel;
+    TypeArena* arena;
+
+    InplaceDemoter(TypeLevel level, TypeArena* arena)
+        : newLevel(level)
+        , arena(arena)
+    {
+    }
+
+    bool demote(TypeId ty)
+    {
+        if (auto level = getMutableLevel(ty))
+        {
+            if (level->subsumesStrict(newLevel))
+            {
+                *level = newLevel;
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    bool visit(TypeId ty, const BoundTypeVar& btyRef) override
+    {
+        return true;
+    }
+
+    bool visit(TypeId ty) override
+    {
+        if (ty->owningArena != arena)
+            return false;
+        return demote(ty);
+    }
+
+    bool visit(TypePackId tp, const FreeTypePack& ftpRef) override
+    {
+        if (tp->owningArena != arena)
+            return false;
+
+        FreeTypePack* ftp = &const_cast<FreeTypePack&>(ftpRef);
+        if (ftp->level.subsumesStrict(newLevel))
+        {
+            ftp->level = newLevel;
+            return true;
+        }
+
+        return false;
+    }
+};
+
 void TypeChecker::checkBlockWithoutRecursionCheck(const ScopePtr& scope, const AstStatBlock& block)
 {
     int subLevel = 0;
@@ -559,7 +624,7 @@ void TypeChecker::checkBlockWithoutRecursionCheck(const ScopePtr& scope, const A
                     tablify(baseTy);
 
                     if (!fun->func->self)
-                        expectedType = getIndexTypeFromType(scope, baseTy, name->index.value, name->indexLocation, false);
+                        expectedType = getIndexTypeFromType(scope, baseTy, name->index.value, name->indexLocation, /* addErrors= */ false);
                     else if (auto ttv = getMutableTableType(baseTy))
                     {
                         if (!baseTy->persistent && ttv->state != TableState::Sealed && !ttv->selfTy)
@@ -579,7 +644,7 @@ void TypeChecker::checkBlockWithoutRecursionCheck(const ScopePtr& scope, const A
                     if (auto name = fun->name->as<AstExprIndexName>())
                     {
                         TypeId exprTy = checkExpr(scope, *name->expr).type;
-                        expectedType = getIndexTypeFromType(scope, exprTy, name->index.value, name->indexLocation, false);
+                        expectedType = getIndexTypeFromType(scope, exprTy, name->index.value, name->indexLocation, /* addErrors= */ false);
                     }
                 }
             }
@@ -634,15 +699,8 @@ LUAU_NOINLINE void TypeChecker::checkBlockTypeAliases(const ScopePtr& scope, std
             TypeId type = bindings[name].type;
             if (get<FreeTypeVar>(follow(type)))
             {
-                if (FFlag::LuauNonCopyableTypeVarFields)
-                {
-                    TypeVar* mty = asMutable(follow(type));
-                    mty->reassign(*errorRecoveryType(anyType));
-                }
-                else
-                {
-                    *asMutable(type) = *errorRecoveryType(anyType);
-                }
+                TypeVar* mty = asMutable(follow(type));
+                mty->reassign(*errorRecoveryType(anyType));
 
                 reportError(TypeError{typealias->location, OccursCheckFailed{}});
             }
@@ -1206,7 +1264,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin)
         iterTy = instantiate(scope, checkExpr(scope, *firstValue).type, firstValue->location);
     }
 
-    if (std::optional<TypeId> iterMM = findMetatableEntry(iterTy, "__iter", firstValue->location))
+    if (std::optional<TypeId> iterMM = findMetatableEntry(iterTy, "__iter", firstValue->location, /* addErrors= */ true))
     {
         // if __iter metamethod is present, it will be called and the results are going to be called as if they are functions
         // TODO: this needs to typecheck all returned values by __iter as if they were for loop arguments
@@ -1253,7 +1311,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin)
         for (TypeId var : varTypes)
             unify(varTy, var, forin.location);
 
-        if (!get<ErrorTypeVar>(iterTy) && !get<AnyTypeVar>(iterTy) && !get<FreeTypeVar>(iterTy))
+        if (!get<ErrorTypeVar>(iterTy) && !get<AnyTypeVar>(iterTy) && !get<FreeTypeVar>(iterTy) && !get<NeverTypeVar>(iterTy))
             reportError(firstValue->location, CannotCallNonFunction{iterTy});
 
         return check(loopScope, *forin.body);
@@ -1350,7 +1408,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco
         TypeId exprTy = checkExpr(scope, *name->expr).type;
         TableTypeVar* ttv = getMutableTableType(exprTy);
 
-        if (!getIndexTypeFromType(scope, exprTy, name->index.value, name->indexLocation, false))
+        if (!getIndexTypeFromType(scope, exprTy, name->index.value, name->indexLocation, /* addErrors= */ false))
         {
             if (ttv || isTableIntersection(exprTy))
                 reportError(TypeError{function.location, CannotExtendTable{exprTy, CannotExtendTable::Property, name->index.value}});
@@ -1376,6 +1434,12 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco
 
         checkFunctionBody(funScope, ty, *function.func);
 
+        if (FFlag::LuauUnknownAndNeverType)
+        {
+            InplaceDemoter demoter{funScope->level, &currentModule->internalTypes};
+            demoter.traverse(ty);
+        }
+
         if (ttv && ttv->state != TableState::Sealed)
             ttv->props[name->index.value] = {follow(quantify(funScope, ty, name->indexLocation)), /* deprecated */ false, {}, name->indexLocation};
     }
@@ -1729,7 +1793,7 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
     else if (auto a = expr.as<AstExprUnary>())
         result = checkExpr(scope, *a);
     else if (auto a = expr.as<AstExprBinary>())
-        result = checkExpr(scope, *a);
+        result = checkExpr(scope, *a, FFlag::LuauBinaryNeedsExpectedTypesToo ? expectedType : std::nullopt);
     else if (auto a = expr.as<AstExprTypeAssertion>())
         result = checkExpr(scope, *a);
     else if (auto a = expr.as<AstExprError>())
@@ -1851,41 +1915,56 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
 
     lhsType = stripFromNilAndReport(lhsType, expr.expr->location);
 
-    if (std::optional<TypeId> ty = getIndexTypeFromType(scope, lhsType, name, expr.location, true))
+    if (std::optional<TypeId> ty = getIndexTypeFromType(scope, lhsType, name, expr.location, /* addErrors= */ true))
         return {*ty};
 
     return {errorRecoveryType(scope)};
 }
 
-std::optional<TypeId> TypeChecker::findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location)
+std::optional<TypeId> TypeChecker::findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location, bool addErrors)
 {
     ErrorVec errors;
     auto result = Luau::findTablePropertyRespectingMeta(errors, lhsType, name, location);
-    reportErrors(errors);
+    if (!FFlag::LuauIndexSilenceErrors || addErrors)
+        reportErrors(errors);
     return result;
 }
 
-std::optional<TypeId> TypeChecker::findMetatableEntry(TypeId type, std::string entry, const Location& location)
+std::optional<TypeId> TypeChecker::findMetatableEntry(TypeId type, std::string entry, const Location& location, bool addErrors)
 {
     ErrorVec errors;
     auto result = Luau::findMetatableEntry(errors, type, entry, location);
-    reportErrors(errors);
+    if (!FFlag::LuauIndexSilenceErrors || addErrors)
+        reportErrors(errors);
     return result;
 }
 
 std::optional<TypeId> TypeChecker::getIndexTypeFromType(
-    const ScopePtr& scope, TypeId type, const std::string& name, const Location& location, bool addErrors)
+    const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors)
+{
+    size_t errorCount = currentModule->errors.size();
+
+    std::optional<TypeId> result = getIndexTypeFromTypeImpl(scope, type, name, location, addErrors);
+
+    if (FFlag::LuauIndexSilenceErrors && !addErrors)
+        LUAU_ASSERT(errorCount == currentModule->errors.size());
+
+    return result;
+}
+
+std::optional<TypeId> TypeChecker::getIndexTypeFromTypeImpl(
+    const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors)
 {
     type = follow(type);
 
-    if (get<ErrorTypeVar>(type) || get<AnyTypeVar>(type))
+    if (get<ErrorTypeVar>(type) || get<AnyTypeVar>(type) || get<NeverTypeVar>(type))
         return type;
 
     tablify(type);
 
     if (isString(type))
     {
-        std::optional<TypeId> mtIndex = findMetatableEntry(stringType, "__index", location);
+        std::optional<TypeId> mtIndex = findMetatableEntry(stringType, "__index", location, addErrors);
         LUAU_ASSERT(mtIndex);
         type = *mtIndex;
     }
@@ -1919,7 +1998,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromType(
             return result;
         }
 
-        if (auto found = findTablePropertyRespectingMeta(type, name, location))
+        if (auto found = findTablePropertyRespectingMeta(type, name, location, addErrors))
             return *found;
     }
     else if (const ClassTypeVar* cls = get<ClassTypeVar>(type))
@@ -1941,7 +2020,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromType(
             if (get<AnyTypeVar>(follow(t)))
                 return t;
 
-            if (std::optional<TypeId> ty = getIndexTypeFromType(scope, t, name, location, false))
+            if (std::optional<TypeId> ty = getIndexTypeFromType(scope, t, name, location, /* addErrors= */ false))
                 goodOptions.push_back(*ty);
             else
                 badOptions.push_back(t);
@@ -1972,6 +2051,8 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromType(
         else
         {
             std::vector<TypeId> result = reduceUnion(goodOptions);
+            if (FFlag::LuauUnknownAndNeverType && result.empty())
+                return neverType;
 
             if (result.size() == 1)
                 return result[0];
@@ -1987,7 +2068,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromType(
         {
             RecursionLimiter _rl(&recursionCount, FInt::LuauTypeInferRecursionLimit);
 
-            if (std::optional<TypeId> ty = getIndexTypeFromType(scope, t, name, location, false))
+            if (std::optional<TypeId> ty = getIndexTypeFromType(scope, t, name, location, /* addErrors= */ false))
                 parts.push_back(*ty);
         }
 
@@ -2017,6 +2098,9 @@ std::vector<TypeId> TypeChecker::reduceUnion(const std::vector<TypeId>& types)
     for (TypeId t : types)
     {
         t = follow(t);
+        if (get<NeverTypeVar>(t))
+            continue;
+
         if (get<ErrorTypeVar>(t) || get<AnyTypeVar>(t))
             return {t};
 
@@ -2028,6 +2112,8 @@ std::vector<TypeId> TypeChecker::reduceUnion(const std::vector<TypeId>& types)
                 {
                     if (FFlag::LuauNormalizeFlagIsConservative)
                         ty = follow(ty);
+                    if (get<NeverTypeVar>(ty))
+                        continue;
                     if (get<ErrorTypeVar>(ty) || get<AnyTypeVar>(ty))
                         return {ty};
 
@@ -2041,6 +2127,8 @@ std::vector<TypeId> TypeChecker::reduceUnion(const std::vector<TypeId>& types)
                 for (TypeId ty : r)
                 {
                     ty = follow(ty);
+                    if (get<NeverTypeVar>(ty))
+                        continue;
                     if (get<ErrorTypeVar>(ty) || get<AnyTypeVar>(ty))
                         return {ty};
 
@@ -2314,14 +2402,14 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
         return {booleanType, {NotPredicate{std::move(result.predicates)}}};
     case AstExprUnary::Minus:
     {
-        const bool operandIsAny = get<AnyTypeVar>(operandType) || get<ErrorTypeVar>(operandType);
+        const bool operandIsAny = get<AnyTypeVar>(operandType) || get<ErrorTypeVar>(operandType) || get<NeverTypeVar>(operandType);
 
         if (operandIsAny)
             return {operandType};
 
         if (typeCouldHaveMetatable(operandType))
         {
-            if (auto fnt = findMetatableEntry(operandType, "__unm", expr.location))
+            if (auto fnt = findMetatableEntry(operandType, "__unm", expr.location, /* addErrors= */ true))
             {
                 TypeId actualFunctionType = instantiate(scope, *fnt, expr.location);
                 TypePackId arguments = addTypePack({operandType});
@@ -2355,14 +2443,14 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
 
         operandType = stripFromNilAndReport(operandType, expr.location);
 
-        if (get<ErrorTypeVar>(operandType))
-            return {errorRecoveryType(scope)};
+        if (get<ErrorTypeVar>(operandType) || get<NeverTypeVar>(operandType))
+            return {!FFlag::LuauUnknownAndNeverType ? errorRecoveryType(scope) : operandType};
 
         DenseHashSet<TypeId> seen{nullptr};
 
         if (FFlag::LuauCheckLenMT && typeCouldHaveMetatable(operandType))
         {
-            if (auto fnt = findMetatableEntry(operandType, "__len", expr.location))
+            if (auto fnt = findMetatableEntry(operandType, "__len", expr.location, /* addErrors= */ true))
             {
                 TypeId actualFunctionType = instantiate(scope, *fnt, expr.location);
                 TypePackId arguments = addTypePack({operandType});
@@ -2433,6 +2521,9 @@ TypeId TypeChecker::unionOfTypes(TypeId a, TypeId b, const Location& location, b
         return a;
 
     std::vector<TypeId> types = reduceUnion({a, b});
+    if (FFlag::LuauUnknownAndNeverType && types.empty())
+        return neverType;
+
     if (types.size() == 1)
         return types[0];
 
@@ -2485,7 +2576,7 @@ TypeId TypeChecker::checkRelationalOperation(
 
     // If we know nothing at all about the lhs type, we can usually say nothing about the result.
     // The notable exception to this is the equality and inequality operators, which always produce a boolean.
-    const bool lhsIsAny = get<AnyTypeVar>(lhsType) || get<ErrorTypeVar>(lhsType);
+    const bool lhsIsAny = get<AnyTypeVar>(lhsType) || get<ErrorTypeVar>(lhsType) || get<NeverTypeVar>(lhsType);
 
     // Peephole check for `cond and a or b -> type(a)|type(b)`
     // TODO: Kill this when singleton types arrive. :(
@@ -2508,7 +2599,7 @@ TypeId TypeChecker::checkRelationalOperation(
         if (isNonstrictMode() && (isNil(lhsType) || isNil(rhsType)))
             return booleanType;
 
-        const bool rhsIsAny = get<AnyTypeVar>(rhsType) || get<ErrorTypeVar>(rhsType);
+        const bool rhsIsAny = get<AnyTypeVar>(rhsType) || get<ErrorTypeVar>(rhsType) || get<NeverTypeVar>(rhsType);
         if (lhsIsAny || rhsIsAny)
             return booleanType;
 
@@ -2596,7 +2687,7 @@ TypeId TypeChecker::checkRelationalOperation(
 
         if (leftMetatable)
         {
-            std::optional<TypeId> metamethod = findMetatableEntry(lhsType, metamethodName, expr.location);
+            std::optional<TypeId> metamethod = findMetatableEntry(lhsType, metamethodName, expr.location, /* addErrors= */ true);
             if (metamethod)
             {
                 if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(*metamethod))
@@ -2757,9 +2848,9 @@ TypeId TypeChecker::checkBinaryOperation(
         };
 
         std::string op = opToMetaTableEntry(expr.op);
-        if (auto fnt = findMetatableEntry(lhsType, op, expr.location))
+        if (auto fnt = findMetatableEntry(lhsType, op, expr.location, /* addErrors= */ true))
             return checkMetatableCall(*fnt, lhsType, rhsType);
-        if (auto fnt = findMetatableEntry(rhsType, op, expr.location))
+        if (auto fnt = findMetatableEntry(rhsType, op, expr.location, /* addErrors= */ true))
         {
             // Note the intentionally reversed arguments here.
             return checkMetatableCall(*fnt, rhsType, lhsType);
@@ -2793,27 +2884,27 @@ TypeId TypeChecker::checkBinaryOperation(
     }
 }
 
-WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExprBinary& expr)
+WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExprBinary& expr, std::optional<TypeId> expectedType)
 {
     if (expr.op == AstExprBinary::And)
     {
-        auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left);
+        auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left, expectedType);
 
         ScopePtr innerScope = childScope(scope, expr.location);
         resolve(lhsPredicates, innerScope, true);
 
-        auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right);
+        auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right, expectedType);
 
         return {checkBinaryOperation(scope, expr, lhsTy, rhsTy), {AndPredicate{std::move(lhsPredicates), std::move(rhsPredicates)}}};
     }
     else if (expr.op == AstExprBinary::Or)
     {
-        auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left);
+        auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left, expectedType);
 
         ScopePtr innerScope = childScope(scope, expr.location);
         resolve(lhsPredicates, innerScope, false);
 
-        auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right);
+        auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right, expectedType);
 
         // Because of C++, I'm not sure if lhsPredicates was not moved out by the time we call checkBinaryOperation.
         TypeId result = checkBinaryOperation(scope, expr, lhsTy, rhsTy, lhsPredicates);
@@ -2824,6 +2915,8 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
         if (auto predicate = tryGetTypeGuardPredicate(expr))
             return {booleanType, {std::move(*predicate)}};
 
+        // For these, passing expectedType is worse than simply forcing them, because their implementation
+        // may inadvertently check if expectedTypes exist first and use it, instead of forceSingleton first.
         WithPredicate<TypeId> lhs = checkExpr(scope, *expr.left, std::nullopt, /*forceSingleton=*/true);
         WithPredicate<TypeId> rhs = checkExpr(scope, *expr.right, std::nullopt, /*forceSingleton=*/true);
 
@@ -2842,6 +2935,7 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
     }
     else
     {
+        // Expected types are not useful for other binary operators.
         WithPredicate<TypeId> lhs = checkExpr(scope, *expr.left);
         WithPredicate<TypeId> rhs = checkExpr(scope, *expr.right);
 
@@ -2896,6 +2990,8 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
         return {trueType.type};
 
     std::vector<TypeId> types = reduceUnion({trueType.type, falseType.type});
+    if (FFlag::LuauUnknownAndNeverType && types.empty())
+        return {neverType};
     return {types.size() == 1 ? types[0] : addType(UnionTypeVar{std::move(types)})};
 }
 
@@ -2927,7 +3023,10 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExpr& exp
 TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprLocal& expr)
 {
     if (std::optional<TypeId> ty = scope->lookup(expr.local))
-        return *ty;
+    {
+        ty = follow(*ty);
+        return get<NeverTypeVar>(*ty) ? unknownType : *ty;
+    }
 
     reportError(expr.location, UnknownSymbol{expr.local->name.value, UnknownSymbol::Binding});
     return errorRecoveryType(scope);
@@ -2941,7 +3040,10 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprGloba
     const auto it = moduleScope->bindings.find(expr.name);
 
     if (it != moduleScope->bindings.end())
-        return it->second.typeId;
+    {
+        TypeId ty = follow(it->second.typeId);
+        return get<NeverTypeVar>(ty) ? unknownType : ty;
+    }
 
     TypeId result = freshType(scope);
     Binding& binding = moduleScope->bindings[expr.name];
@@ -2962,6 +3064,9 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
     if (get<ErrorTypeVar>(lhs) || get<AnyTypeVar>(lhs))
         return lhs;
 
+    if (get<NeverTypeVar>(lhs))
+        return unknownType;
+
     tablify(lhs);
 
     Name name = expr.index.value;
@@ -3023,7 +3128,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
     }
     else if (get<IntersectionTypeVar>(lhs))
     {
-        if (std::optional<TypeId> ty = getIndexTypeFromType(scope, lhs, name, expr.location, false))
+        if (std::optional<TypeId> ty = getIndexTypeFromType(scope, lhs, name, expr.location, /* addErrors= */ false))
             return *ty;
 
         // If intersection has a table part, report that it cannot be extended just as a sealed table
@@ -3050,6 +3155,9 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
     if (get<AnyTypeVar>(exprType) || get<ErrorTypeVar>(exprType))
         return exprType;
 
+    if (get<NeverTypeVar>(exprType))
+        return unknownType;
+
     AstExprConstantString* value = expr.index->as<AstExprConstantString>();
 
     if (value)
@@ -3156,7 +3264,7 @@ TypeId TypeChecker::checkFunctionName(const ScopePtr& scope, AstExpr& funName, T
 
         if (!ttv || ttv->state == TableState::Sealed)
         {
-            if (auto ty = getIndexTypeFromType(scope, lhsType, indexName->index.value, indexName->indexLocation, false))
+            if (auto ty = getIndexTypeFromType(scope, lhsType, indexName->index.value, indexName->indexLocation, /* addErrors= */ false))
                 return *ty;
 
             return errorRecoveryType(scope);
@@ -3228,9 +3336,12 @@ std::pair<TypeId, ScopePtr> TypeChecker::checkFunctionSignature(const ScopePtr&
             }
         }
 
-        // We do not infer type binders, so if a generic function is required we do not propagate
-        if (expectedFunctionType && !(expectedFunctionType->generics.empty() && expectedFunctionType->genericPacks.empty()))
-            expectedFunctionType = nullptr;
+        if (!FFlag::LuauCheckGenericHOFTypes)
+        {
+            // We do not infer type binders, so if a generic function is required we do not propagate
+            if (expectedFunctionType && !(expectedFunctionType->generics.empty() && expectedFunctionType->genericPacks.empty()))
+                expectedFunctionType = nullptr;
+        }
     }
 
     auto [generics, genericPacks] = createGenericTypes(funScope, std::nullopt, expr, expr.generics, expr.genericPacks);
@@ -3240,7 +3351,8 @@ std::pair<TypeId, ScopePtr> TypeChecker::checkFunctionSignature(const ScopePtr&
         retPack = resolveTypePack(funScope, *expr.returnAnnotation);
     else if (FFlag::LuauReturnTypeInferenceInNonstrict ? (!FFlag::LuauLowerBoundsCalculation && isNonstrictMode()) : isNonstrictMode())
         retPack = anyTypePack;
-    else if (expectedFunctionType)
+    else if (expectedFunctionType &&
+             (!FFlag::LuauCheckGenericHOFTypes || (expectedFunctionType->generics.empty() && expectedFunctionType->genericPacks.empty())))
     {
         auto [head, tail] = flatten(expectedFunctionType->retTypes);
 
@@ -3371,16 +3483,50 @@ std::pair<TypeId, ScopePtr> TypeChecker::checkFunctionSignature(const ScopePtr&
     defn.originalNameLocation = originalName.value_or(Location(expr.location.begin, 0));
 
     std::vector<TypeId> genericTys;
-    genericTys.reserve(generics.size());
-    std::transform(generics.begin(), generics.end(), std::back_inserter(genericTys), [](auto&& el) {
-        return el.ty;
-    });
+    // if we have a generic expected function type and no generics, we should use the expected ones.
+    if (FFlag::LuauCheckGenericHOFTypes)
+    {
+        if (expectedFunctionType && generics.empty())
+        {
+            genericTys = expectedFunctionType->generics;
+        }
+        else
+        {
+            genericTys.reserve(generics.size());
+            for (const GenericTypeDefinition& generic : generics)
+                genericTys.push_back(generic.ty);
+        }
+    }
+    else
+    {
+        genericTys.reserve(generics.size());
+        std::transform(generics.begin(), generics.end(), std::back_inserter(genericTys), [](auto&& el) {
+            return el.ty;
+        });
+    }
 
     std::vector<TypePackId> genericTps;
-    genericTps.reserve(genericPacks.size());
-    std::transform(genericPacks.begin(), genericPacks.end(), std::back_inserter(genericTps), [](auto&& el) {
-        return el.tp;
-    });
+    // if we have a generic expected function type and no generic typepacks, we should use the expected ones.
+    if (FFlag::LuauCheckGenericHOFTypes)
+    {
+        if (expectedFunctionType && genericPacks.empty())
+        {
+            genericTps = expectedFunctionType->genericPacks;
+        }
+        else
+        {
+            genericTps.reserve(genericPacks.size());
+            for (const GenericTypePackDefinition& generic : genericPacks)
+                genericTps.push_back(generic.tp);
+        }
+    }
+    else
+    {
+        genericTps.reserve(genericPacks.size());
+        std::transform(genericPacks.begin(), genericPacks.end(), std::back_inserter(genericTps), [](auto&& el) {
+            return el.tp;
+        });
+    }
 
     TypeId funTy =
         addType(FunctionTypeVar(funScope->level, std::move(genericTys), std::move(genericTps), argPack, retPack, std::move(defn), bool(expr.self)));
@@ -3474,9 +3620,22 @@ void TypeChecker::checkFunctionBody(const ScopePtr& scope, TypeId ty, const AstE
 }
 
 WithPredicate<TypePackId> TypeChecker::checkExprPack(const ScopePtr& scope, const AstExpr& expr)
+{
+    if (FFlag::LuauUnknownAndNeverType)
+    {
+        WithPredicate<TypePackId> result = checkExprPackHelper(scope, expr);
+        if (containsNever(result.type))
+            return {uninhabitableTypePack};
+        return result;
+    }
+    else
+        return checkExprPackHelper(scope, expr);
+}
+
+WithPredicate<TypePackId> TypeChecker::checkExprPackHelper(const ScopePtr& scope, const AstExpr& expr)
 {
     if (auto a = expr.as<AstExprCall>())
-        return checkExprPack(scope, *a);
+        return checkExprPackHelper(scope, *a);
     else if (expr.is<AstExprVarargs>())
     {
         if (!scope->varargPack)
@@ -3739,7 +3898,7 @@ void TypeChecker::checkArgumentList(
     }
 }
 
-WithPredicate<TypePackId> TypeChecker::checkExprPack(const ScopePtr& scope, const AstExprCall& expr)
+WithPredicate<TypePackId> TypeChecker::checkExprPackHelper(const ScopePtr& scope, const AstExprCall& expr)
 {
     // evaluate type of function
     // decompose an intersection into its component overloads
@@ -3763,7 +3922,7 @@ WithPredicate<TypePackId> TypeChecker::checkExprPack(const ScopePtr& scope, cons
         selfType = checkExpr(scope, *indexExpr->expr).type;
         selfType = stripFromNilAndReport(selfType, expr.func->location);
 
-        if (std::optional<TypeId> propTy = getIndexTypeFromType(scope, selfType, indexExpr->index.value, expr.location, true))
+        if (std::optional<TypeId> propTy = getIndexTypeFromType(scope, selfType, indexExpr->index.value, expr.location, /* addErrors= */ true))
         {
             functionType = *propTy;
             actualFunctionType = instantiate(scope, functionType, expr.func->location);
@@ -3813,11 +3972,25 @@ WithPredicate<TypePackId> TypeChecker::checkExprPack(const ScopePtr& scope, cons
     if (get<Unifiable::Error>(argPack))
         return {errorRecoveryTypePack(scope)};
 
-    TypePack* args = getMutable<TypePack>(argPack);
-    LUAU_ASSERT(args != nullptr);
+    TypePack* args = nullptr;
+    if (FFlag::LuauUnknownAndNeverType)
+    {
+        if (expr.self)
+        {
+            argPack = addTypePack(TypePack{{selfType}, argPack});
+            argListResult.type = argPack;
+        }
+        args = getMutable<TypePack>(argPack);
+        LUAU_ASSERT(args);
+    }
+    else
+    {
+        args = getMutable<TypePack>(argPack);
+        LUAU_ASSERT(args != nullptr);
 
-    if (expr.self)
-        args->head.insert(args->head.begin(), selfType);
+        if (expr.self)
+            args->head.insert(args->head.begin(), selfType);
+    }
 
     std::vector<Location> argLocations;
     argLocations.reserve(expr.args.size + 1);
@@ -3876,7 +4049,10 @@ std::vector<std::optional<TypeId>> TypeChecker::getExpectedTypesForCall(const st
             else
             {
                 std::vector<TypeId> result = reduceUnion({*el, ty});
-                el = result.size() == 1 ? result[0] : addType(UnionTypeVar{std::move(result)});
+                if (FFlag::LuauUnknownAndNeverType && result.empty())
+                    el = neverType;
+                else
+                    el = result.size() == 1 ? result[0] : addType(UnionTypeVar{std::move(result)});
             }
         }
     };
@@ -3930,6 +4106,9 @@ std::optional<WithPredicate<TypePackId>> TypeChecker::checkCallOverload(const Sc
         return {{errorRecoveryTypePack(scope)}};
     }
 
+    if (get<NeverTypeVar>(fn))
+        return {{uninhabitableTypePack}};
+
     if (auto ftv = get<FreeTypeVar>(fn))
     {
         // fn is one of the overloads of actualFunctionType, which
@@ -3975,7 +4154,7 @@ std::optional<WithPredicate<TypePackId>> TypeChecker::checkCallOverload(const Sc
     // Might be a callable table
     if (const MetatableTypeVar* mttv = get<MetatableTypeVar>(fn))
     {
-        if (std::optional<TypeId> ty = getIndexTypeFromType(scope, mttv->metatable, "__call", expr.func->location, false))
+        if (std::optional<TypeId> ty = getIndexTypeFromType(scope, mttv->metatable, "__call", expr.func->location, /* addErrors= */ false))
         {
             // Construct arguments with 'self' added in front
             TypePackId metaCallArgPack = addTypePack(TypePackVar(TypePack{args->head, args->tail}));
@@ -4202,6 +4381,7 @@ void TypeChecker::reportOverloadResolutionError(const ScopePtr& scope, const Ast
 WithPredicate<TypePackId> TypeChecker::checkExprList(const ScopePtr& scope, const Location& location, const AstArray<AstExpr*>& exprs,
     bool substituteFreeForNil, const std::vector<bool>& instantiateGenerics, const std::vector<std::optional<TypeId>>& expectedTypes)
 {
+    bool uninhabitable = false;
     TypePackId pack = addTypePack(TypePack{});
     PredicateVec predicates; // At the moment we will be pushing all predicate sets into this. Do we need some way to split them up?
 
@@ -4232,7 +4412,13 @@ WithPredicate<TypePackId> TypeChecker::checkExprList(const ScopePtr& scope, cons
             auto [typePack, exprPredicates] = checkExprPack(scope, *expr);
             insert(exprPredicates);
 
-            if (std::optional<TypeId> firstTy = first(typePack))
+            if (FFlag::LuauUnknownAndNeverType && containsNever(typePack))
+            {
+                // f(), g() where f() returns (never, string) or (string, never) means this whole TypePackId is uninhabitable, so return (never, ...never)
+                uninhabitable = true;
+                continue;
+            }
+            else if (std::optional<TypeId> firstTy = first(typePack))
             {
                 if (!currentModule->astTypes.find(expr))
                     currentModule->astTypes[expr] = follow(*firstTy);
@@ -4248,6 +4434,13 @@ WithPredicate<TypePackId> TypeChecker::checkExprList(const ScopePtr& scope, cons
             auto [type, exprPredicates] = checkExpr(scope, *expr, expectedType);
             insert(exprPredicates);
 
+            if (FFlag::LuauUnknownAndNeverType && get<NeverTypeVar>(type))
+            {
+                // f(), g() where f() returns (never, string) or (string, never) means this whole TypePackId is uninhabitable, so return (never, ...never)
+                uninhabitable = true;
+                continue;
+            }
+
             TypeId actualType = substituteFreeForNil && expr->is<AstExprConstantNil>() ? freshType(scope) : type;
 
             if (instantiateGenerics.size() > i && instantiateGenerics[i])
@@ -4272,6 +4465,8 @@ WithPredicate<TypePackId> TypeChecker::checkExprList(const ScopePtr& scope, cons
     for (TxnLog& log : inverseLogs)
         log.commit();
 
+    if (FFlag::LuauUnknownAndNeverType && uninhabitable)
+        return {uninhabitableTypePack};
     return {pack, predicates};
 }
 
@@ -4830,7 +5025,7 @@ TypeIdPredicate TypeChecker::mkTruthyPredicate(bool sense)
     };
 }
 
-std::optional<TypeId> TypeChecker::filterMap(TypeId type, TypeIdPredicate predicate)
+std::optional<TypeId> TypeChecker::filterMapImpl(TypeId type, TypeIdPredicate predicate)
 {
     std::vector<TypeId> types = Luau::filterMap(type, predicate);
     if (!types.empty())
@@ -4838,7 +5033,21 @@ std::optional<TypeId> TypeChecker::filterMap(TypeId type, TypeIdPredicate predic
     return std::nullopt;
 }
 
-std::optional<TypeId> TypeChecker::pickTypesFromSense(TypeId type, bool sense)
+std::pair<std::optional<TypeId>, bool> TypeChecker::filterMap(TypeId type, TypeIdPredicate predicate)
+{
+    if (FFlag::LuauUnknownAndNeverType)
+    {
+        TypeId ty = filterMapImpl(type, predicate).value_or(neverType);
+        return {ty, !bool(get<NeverTypeVar>(ty))};
+    }
+    else
+    {
+        std::optional<TypeId> ty = filterMapImpl(type, predicate);
+        return {ty, bool(ty)};
+    }
+}
+
+std::pair<std::optional<TypeId>, bool> TypeChecker::pickTypesFromSense(TypeId type, bool sense)
 {
     return filterMap(type, mkTruthyPredicate(sense));
 }
@@ -5465,10 +5674,18 @@ void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const
     // If we do not have a key, it means we're not trying to discriminate anything, so it's a simple matter of just filtering for a subset.
     if (!key)
     {
-        if (std::optional<TypeId> result = filterMap(*ty, predicate))
+        auto [result, ok] = filterMap(*ty, predicate);
+        if (FFlag::LuauUnknownAndNeverType)
+        {
             addRefinement(refis, *target, *result);
+        }
         else
-            addRefinement(refis, *target, errorRecoveryType(scope));
+        {
+            if (ok)
+                addRefinement(refis, *target, *result);
+            else
+                addRefinement(refis, *target, errorRecoveryType(scope));
+        }
 
         return;
     }
@@ -5484,17 +5701,29 @@ void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const
     {
         std::optional<TypeId> discriminantTy;
         if (auto field = Luau::get<Field>(*key)) // need to fully qualify Luau::get because of ADL.
-            discriminantTy = getIndexTypeFromType(scope, option, field->key, Location(), false);
+            discriminantTy = getIndexTypeFromType(scope, option, field->key, Location(), /* addErrors= */ false);
         else
             LUAU_ASSERT(!"Unhandled LValue alternative?");
 
         if (!discriminantTy)
             return; // Do nothing. An error was already reported, as per usual.
 
-        if (std::optional<TypeId> result = filterMap(*discriminantTy, predicate))
+        auto [result, ok] = filterMap(*discriminantTy, predicate);
+        if (FFlag::LuauUnknownAndNeverType)
         {
-            viableTargetOptions.insert(option);
-            viableChildOptions.insert(*result);
+            if (!get<NeverTypeVar>(*result))
+            {
+                viableTargetOptions.insert(option);
+                viableChildOptions.insert(*result);
+            }
+        }
+        else
+        {
+            if (ok)
+            {
+                viableTargetOptions.insert(option);
+                viableChildOptions.insert(*result);
+            }
         }
     }
 
@@ -5573,7 +5802,7 @@ std::optional<TypeId> TypeChecker::resolveLValue(const ScopePtr& scope, const LV
                 continue;
             else if (auto field = get<Field>(key))
             {
-                found = getIndexTypeFromType(scope, *found, field->key, Location(), false);
+                found = getIndexTypeFromType(scope, *found, field->key, Location(), /* addErrors= */ false);
                 if (!found)
                     return std::nullopt; // Turns out this type doesn't have the property at all. We're done.
             }
@@ -5753,6 +5982,9 @@ void TypeChecker::resolve(const TypeGuardPredicate& typeguardP, RefinementMap& r
     auto mkFilter = [](ConditionFunc f, std::optional<TypeId> other = std::nullopt) -> SenseToTypeIdPredicate {
         return [f, other](bool sense) -> TypeIdPredicate {
             return [f, other, sense](TypeId ty) -> std::optional<TypeId> {
+                if (FFlag::LuauUnknownAndNeverType && sense && get<UnknownTypeVar>(ty))
+                    return other.value_or(ty);
+
                 if (f(ty) == sense)
                     return ty;
 
@@ -5860,8 +6092,15 @@ std::vector<TypeId> TypeChecker::unTypePack(const ScopePtr& scope, TypePackId tp
     for (size_t i = 0; i < expectedLength; ++i)
         expectedPack->head.push_back(freshType(scope));
 
+    size_t oldErrorsSize = currentModule->errors.size();
+
     unify(tp, expectedTypePack, location);
 
+    // HACK: tryUnify would undo the changes to the expectedTypePack if the length mismatches, but
+    // we want to tie up free types to be error types, so we do this instead.
+    if (FFlag::LuauUnknownAndNeverType)
+        currentModule->errors.resize(oldErrorsSize);
+
     for (TypeId& tp : expectedPack->head)
         tp = follow(tp);
 
diff --git a/Analysis/src/TypePack.cpp b/Analysis/src/TypePack.cpp
index 82451bd1..d4544483 100644
--- a/Analysis/src/TypePack.cpp
+++ b/Analysis/src/TypePack.cpp
@@ -5,8 +5,6 @@
 
 #include <stdexcept>
 
-LUAU_FASTFLAG(LuauNonCopyableTypeVarFields)
-
 namespace Luau
 {
 
@@ -40,19 +38,10 @@ TypePackVar& TypePackVar::operator=(TypePackVariant&& tp)
 
 TypePackVar& TypePackVar::operator=(const TypePackVar& rhs)
 {
-    if (FFlag::LuauNonCopyableTypeVarFields)
-    {
-        LUAU_ASSERT(owningArena == rhs.owningArena);
-        LUAU_ASSERT(!rhs.persistent);
+    LUAU_ASSERT(owningArena == rhs.owningArena);
+    LUAU_ASSERT(!rhs.persistent);
 
-        reassign(rhs);
-    }
-    else
-    {
-        ty = rhs.ty;
-        persistent = rhs.persistent;
-        owningArena = rhs.owningArena;
-    }
+    reassign(rhs);
 
     return *this;
 }
@@ -294,6 +283,16 @@ std::optional<TypeId> first(TypePackId tp, bool ignoreHiddenVariadics)
     return std::nullopt;
 }
 
+TypePackVar* asMutable(TypePackId tp)
+{
+    return const_cast<TypePackVar*>(tp);
+}
+
+TypePack* asMutable(const TypePack* tp)
+{
+    return const_cast<TypePack*>(tp);
+}
+
 bool isEmpty(TypePackId tp)
 {
     tp = follow(tp);
@@ -360,13 +359,25 @@ bool isVariadic(TypePackId tp, const TxnLog& log)
     return false;
 }
 
-TypePackVar* asMutable(TypePackId tp)
+bool containsNever(TypePackId tp)
 {
-    return const_cast<TypePackVar*>(tp);
+    auto it = begin(tp);
+    auto endIt = end(tp);
+
+    while (it != endIt)
+    {
+        if (get<NeverTypeVar>(follow(*it)))
+            return true;
+        ++it;
+    }
+
+    if (auto tail = it.tail())
+    {
+        if (auto vtp = get<VariadicTypePack>(*tail); vtp && get<NeverTypeVar>(follow(vtp->ty)))
+            return true;
+    }
+
+    return false;
 }
 
-TypePack* asMutable(const TypePack* tp)
-{
-    return const_cast<TypePack*>(tp);
-}
 } // namespace Luau
diff --git a/Analysis/src/TypeUtils.cpp b/Analysis/src/TypeUtils.cpp
index 3d97e6eb..66b38cf3 100644
--- a/Analysis/src/TypeUtils.cpp
+++ b/Analysis/src/TypeUtils.cpp
@@ -24,7 +24,7 @@ std::optional<TypeId> findMetatableEntry(ErrorVec& errors, TypeId type, std::str
     const TableTypeVar* mtt = getTableType(unwrapped);
     if (!mtt)
     {
-        errors.push_back(TypeError{location, GenericError{"Metatable was not a table."}});
+        errors.push_back(TypeError{location, GenericError{"Metatable was not a table"}});
         return std::nullopt;
     }
 
diff --git a/Analysis/src/TypeVar.cpp b/Analysis/src/TypeVar.cpp
index ade70d72..f884ad77 100644
--- a/Analysis/src/TypeVar.cpp
+++ b/Analysis/src/TypeVar.cpp
@@ -23,7 +23,9 @@ LUAU_FASTFLAG(DebugLuauFreezeArena)
 LUAU_FASTINTVARIABLE(LuauTypeMaximumStringifierLength, 500)
 LUAU_FASTINTVARIABLE(LuauTableTypeMaximumStringifierLength, 0)
 LUAU_FASTINT(LuauTypeInferRecursionLimit)
-LUAU_FASTFLAG(LuauNonCopyableTypeVarFields)
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
+LUAU_FASTFLAGVARIABLE(LuauDeduceGmatchReturnTypes, false)
+LUAU_FASTFLAGVARIABLE(LuauMaybeGenericIntersectionTypes, false)
 
 namespace Luau
 {
@@ -31,6 +33,9 @@ namespace Luau
 std::optional<WithPredicate<TypePackId>> magicFunctionFormat(
     TypeChecker& typechecker, const ScopePtr& scope, const AstExprCall& expr, WithPredicate<TypePackId> withPredicate);
 
+static std::optional<WithPredicate<TypePackId>> magicFunctionGmatch(
+    TypeChecker& typechecker, const ScopePtr& scope, const AstExprCall& expr, WithPredicate<TypePackId> withPredicate);
+
 TypeId follow(TypeId t)
 {
     return follow(t, [](TypeId t) {
@@ -173,8 +178,8 @@ bool maybeString(TypeId ty)
 {
     ty = follow(ty);
 
-    if (isPrim(ty, PrimitiveTypeVar::String) || get<AnyTypeVar>(ty))
-        return true;
+        if (isPrim(ty, PrimitiveTypeVar::String) || get<AnyTypeVar>(ty))
+            return true;
 
     if (auto utv = get<UnionTypeVar>(ty))
         return std::any_of(begin(utv), end(utv), maybeString);
@@ -194,7 +199,7 @@ bool isOptional(TypeId ty)
 
     ty = follow(ty);
 
-    if (get<AnyTypeVar>(ty))
+    if (get<AnyTypeVar>(ty) || (FFlag::LuauUnknownAndNeverType && get<UnknownTypeVar>(ty)))
         return true;
 
     auto utv = get<UnionTypeVar>(ty);
@@ -334,6 +339,28 @@ bool isGeneric(TypeId ty)
 
 bool maybeGeneric(TypeId ty)
 {
+    if (FFlag::LuauMaybeGenericIntersectionTypes)
+    {
+        ty = follow(ty);
+
+        if (get<FreeTypeVar>(ty))
+            return true;
+
+        if (auto ttv = get<TableTypeVar>(ty))
+        {
+            // TODO: recurse on table types CLI-39914
+            (void)ttv;
+            return true;
+        }
+
+        if (auto itv = get<IntersectionTypeVar>(ty))
+        {
+            return std::any_of(begin(itv), end(itv), maybeGeneric);
+        }
+
+        return isGeneric(ty);
+    }
+
     ty = follow(ty);
     if (get<FreeTypeVar>(ty))
         return true;
@@ -646,20 +673,10 @@ TypeVar& TypeVar::operator=(TypeVariant&& rhs)
 
 TypeVar& TypeVar::operator=(const TypeVar& rhs)
 {
-    if (FFlag::LuauNonCopyableTypeVarFields)
-    {
-        LUAU_ASSERT(owningArena == rhs.owningArena);
-        LUAU_ASSERT(!rhs.persistent);
+    LUAU_ASSERT(owningArena == rhs.owningArena);
+    LUAU_ASSERT(!rhs.persistent);
 
-        reassign(rhs);
-    }
-    else
-    {
-        ty = rhs.ty;
-        persistent = rhs.persistent;
-        normal = rhs.normal;
-        owningArena = rhs.owningArena;
-    }
+    reassign(rhs);
 
     return *this;
 }
@@ -676,10 +693,14 @@ static TypeVar threadType_{PrimitiveTypeVar{PrimitiveTypeVar::Thread}, /*persist
 static TypeVar trueType_{SingletonTypeVar{BooleanSingleton{true}}, /*persistent*/ true};
 static TypeVar falseType_{SingletonTypeVar{BooleanSingleton{false}}, /*persistent*/ true};
 static TypeVar anyType_{AnyTypeVar{}, /*persistent*/ true};
+static TypeVar unknownType_{UnknownTypeVar{}, /*persistent*/ true};
+static TypeVar neverType_{NeverTypeVar{}, /*persistent*/ true};
 static TypeVar errorType_{ErrorTypeVar{}, /*persistent*/ true};
 
-static TypePackVar anyTypePack_{VariadicTypePack{&anyType_}, true};
-static TypePackVar errorTypePack_{Unifiable::Error{}};
+static TypePackVar anyTypePack_{VariadicTypePack{&anyType_}, /*persistent*/ true};
+static TypePackVar errorTypePack_{Unifiable::Error{}, /*persistent*/ true};
+static TypePackVar neverTypePack_{VariadicTypePack{&neverType_}, /*persistent*/ true};
+static TypePackVar uninhabitableTypePack_{TypePack{{&neverType_}, &neverTypePack_}, /*persistent*/ true};
 
 SingletonTypes::SingletonTypes()
     : nilType(&nilType_)
@@ -690,7 +711,11 @@ SingletonTypes::SingletonTypes()
     , trueType(&trueType_)
     , falseType(&falseType_)
     , anyType(&anyType_)
+    , unknownType(&unknownType_)
+    , neverType(&neverType_)
     , anyTypePack(&anyTypePack_)
+    , neverTypePack(&neverTypePack_)
+    , uninhabitableTypePack(&uninhabitableTypePack_)
     , arena(new TypeArena)
 {
     TypeId stringMetatable = makeStringMetatable();
@@ -738,6 +763,7 @@ TypeId SingletonTypes::makeStringMetatable()
     const TypeId gsubFunc = makeFunction(*arena, stringType, {}, {}, {stringType, replArgType, optionalNumber}, {}, {stringType, numberType});
     const TypeId gmatchFunc =
         makeFunction(*arena, stringType, {}, {}, {stringType}, {}, {arena->addType(FunctionTypeVar{emptyPack, stringVariadicList})});
+    attachMagicFunction(gmatchFunc, magicFunctionGmatch);
 
     TableTypeVar::Props stringLib = {
         {"byte", {arena->addType(FunctionTypeVar{arena->addTypePack({stringType, optionalNumber, optionalNumber}), numberVariadicList})}},
@@ -911,6 +937,8 @@ const TypeLevel* getLevel(TypeId ty)
         return &ttv->level;
     else if (auto ftv = get<FunctionTypeVar>(ty))
         return &ftv->level;
+    else if (auto ctv = get<ConstrainedTypeVar>(ty))
+        return &ctv->level;
     else
         return nullptr;
 }
@@ -965,94 +993,19 @@ bool isSubclass(const ClassTypeVar* cls, const ClassTypeVar* parent)
     return false;
 }
 
-UnionTypeVarIterator::UnionTypeVarIterator(const UnionTypeVar* utv)
+const std::vector<TypeId>& getTypes(const UnionTypeVar* utv)
 {
-    LUAU_ASSERT(utv);
-
-    if (!utv->options.empty())
-        stack.push_front({utv, 0});
-
-    seen.insert(utv);
+    return utv->options;
 }
 
-UnionTypeVarIterator& UnionTypeVarIterator::operator++()
+const std::vector<TypeId>& getTypes(const IntersectionTypeVar* itv)
 {
-    advance();
-    descend();
-    return *this;
+    return itv->parts;
 }
 
-UnionTypeVarIterator UnionTypeVarIterator::operator++(int)
+const std::vector<TypeId>& getTypes(const ConstrainedTypeVar* ctv)
 {
-    UnionTypeVarIterator copy = *this;
-    ++copy;
-    return copy;
-}
-
-bool UnionTypeVarIterator::operator!=(const UnionTypeVarIterator& rhs)
-{
-    return !(*this == rhs);
-}
-
-bool UnionTypeVarIterator::operator==(const UnionTypeVarIterator& rhs)
-{
-    if (!stack.empty() && !rhs.stack.empty())
-        return stack.front() == rhs.stack.front();
-
-    return stack.empty() && rhs.stack.empty();
-}
-
-const TypeId& UnionTypeVarIterator::operator*()
-{
-    LUAU_ASSERT(!stack.empty());
-
-    descend();
-
-    auto [utv, currentIndex] = stack.front();
-    LUAU_ASSERT(utv);
-    LUAU_ASSERT(currentIndex < utv->options.size());
-
-    const TypeId& ty = utv->options[currentIndex];
-    LUAU_ASSERT(!get<UnionTypeVar>(follow(ty)));
-    return ty;
-}
-
-void UnionTypeVarIterator::advance()
-{
-    while (!stack.empty())
-    {
-        auto& [utv, currentIndex] = stack.front();
-        ++currentIndex;
-
-        if (currentIndex >= utv->options.size())
-            stack.pop_front();
-        else
-            break;
-    }
-}
-
-void UnionTypeVarIterator::descend()
-{
-    while (!stack.empty())
-    {
-        auto [utv, currentIndex] = stack.front();
-        if (auto innerUnion = get<UnionTypeVar>(follow(utv->options[currentIndex])))
-        {
-            // If we're about to descend into a cyclic UnionTypeVar, we should skip over this.
-            // Ideally this should never happen, but alas it does from time to time. :(
-            if (seen.find(innerUnion) != seen.end())
-                advance();
-            else
-            {
-                seen.insert(innerUnion);
-                stack.push_front({innerUnion, 0});
-            }
-
-            continue;
-        }
-
-        break;
-    }
+    return ctv->parts;
 }
 
 UnionTypeVarIterator begin(const UnionTypeVar* utv)
@@ -1065,6 +1018,27 @@ UnionTypeVarIterator end(const UnionTypeVar* utv)
     return UnionTypeVarIterator{};
 }
 
+IntersectionTypeVarIterator begin(const IntersectionTypeVar* itv)
+{
+    return IntersectionTypeVarIterator{itv};
+}
+
+IntersectionTypeVarIterator end(const IntersectionTypeVar* itv)
+{
+    return IntersectionTypeVarIterator{};
+}
+
+ConstrainedTypeVarIterator begin(const ConstrainedTypeVar* ctv)
+{
+    return ConstrainedTypeVarIterator{ctv};
+}
+
+ConstrainedTypeVarIterator end(const ConstrainedTypeVar* ctv)
+{
+    return ConstrainedTypeVarIterator{};
+}
+
+
 static std::vector<TypeId> parseFormatString(TypeChecker& typechecker, const char* data, size_t size)
 {
     const char* options = "cdiouxXeEfgGqs";
@@ -1144,6 +1118,101 @@ std::optional<WithPredicate<TypePackId>> magicFunctionFormat(
     return WithPredicate<TypePackId>{arena.addTypePack({typechecker.stringType})};
 }
 
+static std::vector<TypeId> parsePatternString(TypeChecker& typechecker, const char* data, size_t size)
+{
+    std::vector<TypeId> result;
+    int depth = 0;
+    bool parsingSet = false;
+
+    for (size_t i = 0; i < size; ++i)
+    {
+        if (data[i] == '%')
+        {
+            ++i;
+            if (!parsingSet && i < size && data[i] == 'b')
+                i += 2;
+        }
+        else if (!parsingSet && data[i] == '[')
+        {
+            parsingSet = true;
+            if (i + 1 < size && data[i + 1] == ']')
+                i += 1;
+        }
+        else if (parsingSet && data[i] == ']')
+        {
+            parsingSet = false;
+        }
+        else if (data[i] == '(')
+        {
+            if (parsingSet)
+                continue;
+
+            if (i + 1 < size && data[i + 1] == ')')
+            {
+                i++;
+                result.push_back(typechecker.numberType);
+                continue;
+            }
+
+            ++depth;
+            result.push_back(typechecker.stringType);
+        }
+        else if (data[i] == ')')
+        {
+            if (parsingSet)
+                continue;
+
+            --depth;
+
+            if (depth < 0)
+                break;
+        }
+    }
+
+    if (depth != 0 || parsingSet)
+        return std::vector<TypeId>();
+
+    if (result.empty())
+        result.push_back(typechecker.stringType);
+
+    return result;
+}
+
+static std::optional<WithPredicate<TypePackId>> magicFunctionGmatch(
+    TypeChecker& typechecker, const ScopePtr& scope, const AstExprCall& expr, WithPredicate<TypePackId> withPredicate)
+{
+    if (!FFlag::LuauDeduceGmatchReturnTypes)
+        return std::nullopt;
+
+    auto [paramPack, _predicates] = withPredicate;
+    const auto& [params, tail] = flatten(paramPack);
+
+    if (params.size() != 2)
+        return std::nullopt;
+
+    TypeArena& arena = typechecker.currentModule->internalTypes;
+
+    AstExprConstantString* pattern = nullptr;
+    size_t index = expr.self ? 0 : 1;
+    if (expr.args.size > index)
+        pattern = expr.args.data[index]->as<AstExprConstantString>();
+
+    if (!pattern)
+        return std::nullopt;
+
+    std::vector<TypeId> returnTypes = parsePatternString(typechecker, pattern->value.data, pattern->value.size);
+
+    if (returnTypes.empty())
+        return std::nullopt;
+
+    typechecker.unify(params[0], typechecker.stringType, expr.args.data[0]->location);
+
+    const TypePackId emptyPack = arena.addTypePack({});
+    const TypePackId returnList = arena.addTypePack(returnTypes);
+    const TypeId iteratorType = arena.addType(FunctionTypeVar{emptyPack, returnList});
+    return WithPredicate<TypePackId>{arena.addTypePack({iteratorType})};
+}
+
 std::vector<TypeId> filterMap(TypeId type, TypeIdPredicate predicate)
 {
     type = follow(type);
diff --git a/Analysis/src/Unifier.cpp b/Analysis/src/Unifier.cpp
index 0792a350..44a3b854 100644
--- a/Analysis/src/Unifier.cpp
+++ b/Analysis/src/Unifier.cpp
@@ -19,6 +19,7 @@ LUAU_FASTFLAG(LuauAutocompleteDynamicLimits)
 LUAU_FASTINTVARIABLE(LuauTypeInferLowerBoundsIterationLimit, 2000);
 LUAU_FASTFLAG(LuauLowerBoundsCalculation);
 LUAU_FASTFLAG(LuauErrorRecoveryType);
+LUAU_FASTFLAG(LuauUnknownAndNeverType)
 LUAU_FASTFLAG(LuauQuantifyConstrained)
 
 namespace Luau
@@ -47,33 +48,6 @@ struct PromoteTypeLevels final : TypeVarOnceVisitor
         }
     }
 
-    // TODO cycle and operator() need to be clipped when FFlagLuauUseVisitRecursionLimit is clipped
-    template<typename TID>
-    void cycle(TID)
-    {
-    }
-    template<typename TID, typename T>
-    bool operator()(TID ty, const T&)
-    {
-        return visit(ty);
-    }
-    bool operator()(TypeId ty, const FreeTypeVar& ftv)
-    {
-        return visit(ty, ftv);
-    }
-    bool operator()(TypeId ty, const FunctionTypeVar& ftv)
-    {
-        return visit(ty, ftv);
-    }
-    bool operator()(TypeId ty, const TableTypeVar& ttv)
-    {
-        return visit(ty, ttv);
-    }
-    bool operator()(TypePackId tp, const FreeTypePack& ftp)
-    {
-        return visit(tp, ftp);
-    }
-
     bool visit(TypeId ty) override
     {
         // Type levels of types from other modules are already global, so we don't need to promote anything inside
@@ -103,6 +77,15 @@ struct PromoteTypeLevels final : TypeVarOnceVisitor
         return true;
     }
 
+    bool visit(TypeId ty, const ConstrainedTypeVar&) override
+    {
+        if (!FFlag::LuauUnknownAndNeverType)
+            return visit(ty);
+
+        promote(ty, log.getMutable<ConstrainedTypeVar>(ty));
+        return true;
+    }
+
     bool visit(TypeId ty, const FunctionTypeVar&) override
     {
         // Type levels of types from other modules are already global, so we don't need to promote anything inside
@@ -445,6 +428,14 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
     }
     else if (subFree)
     {
+        if (FFlag::LuauUnknownAndNeverType)
+        {
+            // Normally, if the subtype is free, it should not be bound to any, unknown, or error types.
+            // But for bug compatibility, we'll only apply this rule to unknown. Doing this will silence cascading type errors.
+            if (get<UnknownTypeVar>(superTy))
+                return;
+        }
+
         TypeLevel subLevel = subFree->level;
 
         occursCheck(subTy, superTy);
@@ -468,7 +459,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
         return;
     }
 
-    if (get<ErrorTypeVar>(superTy) || get<AnyTypeVar>(superTy))
+    if (get<ErrorTypeVar>(superTy) || get<AnyTypeVar>(superTy) || get<UnknownTypeVar>(superTy))
         return tryUnifyWithAny(subTy, superTy);
 
     if (get<AnyTypeVar>(subTy))
@@ -485,6 +476,9 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
     if (get<ErrorTypeVar>(subTy))
         return tryUnifyWithAny(superTy, subTy);
 
+    if (get<NeverTypeVar>(subTy))
+        return tryUnifyWithAny(superTy, subTy);
+
     auto& cache = sharedState.cachedUnify;
 
     // What if the types are immutable and we proved their relation before
@@ -1862,6 +1856,7 @@ static void tryUnifyWithAny(std::vector<TypeId>& queue, Unifier& state, DenseHas
 
         if (state.log.getMutable<FreeTypeVar>(ty))
         {
+            // TODO: Only bind if the anyType isn't any, unknown, or error (?)
             state.log.replace(ty, BoundTypeVar{anyType});
         }
         else if (auto fun = state.log.getMutable<FunctionTypeVar>(ty))
@@ -1901,22 +1896,27 @@ static void tryUnifyWithAny(std::vector<TypeId>& queue, Unifier& state, DenseHas
 
 void Unifier::tryUnifyWithAny(TypeId subTy, TypeId anyTy)
 {
-    LUAU_ASSERT(get<AnyTypeVar>(anyTy) || get<ErrorTypeVar>(anyTy));
+    LUAU_ASSERT(get<AnyTypeVar>(anyTy) || get<ErrorTypeVar>(anyTy) || get<UnknownTypeVar>(anyTy) || get<NeverTypeVar>(anyTy));
 
     // These types are not visited in general loop below
     if (get<PrimitiveTypeVar>(subTy) || get<AnyTypeVar>(subTy) || get<ClassTypeVar>(subTy))
         return;
 
-    const TypePackId anyTypePack = types->addTypePack(TypePackVar{VariadicTypePack{getSingletonTypes().anyType}});
-
-    const TypePackId anyTP = get<AnyTypeVar>(anyTy) ? anyTypePack : types->addTypePack(TypePackVar{Unifiable::Error{}});
+    TypePackId anyTp;
+    if (FFlag::LuauUnknownAndNeverType)
+        anyTp = types->addTypePack(TypePackVar{VariadicTypePack{anyTy}});
+    else
+    {
+        const TypePackId anyTypePack = types->addTypePack(TypePackVar{VariadicTypePack{getSingletonTypes().anyType}});
+        anyTp = get<AnyTypeVar>(anyTy) ? anyTypePack : types->addTypePack(TypePackVar{Unifiable::Error{}});
+    }
 
     std::vector<TypeId> queue = {subTy};
 
     sharedState.tempSeenTy.clear();
     sharedState.tempSeenTp.clear();
 
-    Luau::tryUnifyWithAny(queue, *this, sharedState.tempSeenTy, sharedState.tempSeenTp, types, getSingletonTypes().anyType, anyTP);
+    Luau::tryUnifyWithAny(queue, *this, sharedState.tempSeenTy, sharedState.tempSeenTp, types, FFlag::LuauUnknownAndNeverType ? anyTy : getSingletonTypes().anyType, anyTp);
 }
 
 void Unifier::tryUnifyWithAny(TypePackId subTy, TypePackId anyTp)
diff --git a/Ast/src/Parser.cpp b/Ast/src/Parser.cpp
index 70c92555..b7fa7889 100644
--- a/Ast/src/Parser.cpp
+++ b/Ast/src/Parser.cpp
@@ -15,7 +15,6 @@ LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
 LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
 
 LUAU_FASTFLAGVARIABLE(LuauParserFunctionKeywordAsTypeHelp, false)
-LUAU_FASTFLAGVARIABLE(LuauReturnTypeTokenConfusion, false)
 
 LUAU_FASTFLAGVARIABLE(LuauFixNamedFunctionParse, false)
 LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseWrongNamedType, false)
@@ -1134,10 +1133,9 @@ AstTypePack* Parser::parseTypeList(TempVector<AstType*>& result, TempVector<std:
 
 std::optional<AstTypeList> Parser::parseOptionalReturnTypeAnnotation()
 {
-    if (options.allowTypeAnnotations &&
-        (lexer.current().type == ':' || (FFlag::LuauReturnTypeTokenConfusion && lexer.current().type == Lexeme::SkinnyArrow)))
+    if (options.allowTypeAnnotations && (lexer.current().type == ':' || lexer.current().type == Lexeme::SkinnyArrow))
     {
-        if (FFlag::LuauReturnTypeTokenConfusion && lexer.current().type == Lexeme::SkinnyArrow)
+        if (lexer.current().type == Lexeme::SkinnyArrow)
             report(lexer.current().location, "Function return type annotations are written after ':' instead of '->'");
 
         nextLexeme();
@@ -1373,12 +1371,10 @@ AstTypeOrPack Parser::parseFunctionTypeAnnotation(bool allowPack)
     if (FFlag::LuauFixNamedFunctionParse && !names.empty())
         forceFunctionType = true;
 
-    bool returnTypeIntroducer =
-        FFlag::LuauReturnTypeTokenConfusion ? lexer.current().type == Lexeme::SkinnyArrow || lexer.current().type == ':' : false;
+    bool returnTypeIntroducer = lexer.current().type == Lexeme::SkinnyArrow || lexer.current().type == ':';
 
     // Not a function at all. Just a parenthesized type. Or maybe a type pack with a single element
-    if (params.size() == 1 && !varargAnnotation && !forceFunctionType &&
-        (FFlag::LuauReturnTypeTokenConfusion ? !returnTypeIntroducer : lexer.current().type != Lexeme::SkinnyArrow))
+    if (params.size() == 1 && !varargAnnotation && !forceFunctionType && !returnTypeIntroducer)
     {
         if (DFFlag::LuaReportParseWrongNamedType && !names.empty())
             lua_telemetry_parsed_named_non_function_type = true;
@@ -1389,8 +1385,7 @@ AstTypeOrPack Parser::parseFunctionTypeAnnotation(bool allowPack)
             return {params[0], {}};
     }
 
-    if ((FFlag::LuauReturnTypeTokenConfusion ? !returnTypeIntroducer : lexer.current().type != Lexeme::SkinnyArrow) && !forceFunctionType &&
-        allowPack)
+    if (!forceFunctionType && !returnTypeIntroducer && allowPack)
     {
         if (DFFlag::LuaReportParseWrongNamedType && !names.empty())
             lua_telemetry_parsed_named_non_function_type = true;
@@ -1409,7 +1404,7 @@ AstType* Parser::parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray<A
 {
     incrementRecursionCounter("type annotation");
 
-    if (FFlag::LuauReturnTypeTokenConfusion && lexer.current().type == ':')
+    if (lexer.current().type == ':')
     {
         report(lexer.current().location, "Return types in function type annotations are written after '->' instead of ':'");
         lexer.next();
diff --git a/CodeGen/include/Luau/AssemblyBuilderX64.h b/CodeGen/include/Luau/AssemblyBuilderX64.h
index c5979d3c..65883b49 100644
--- a/CodeGen/include/Luau/AssemblyBuilderX64.h
+++ b/CodeGen/include/Luau/AssemblyBuilderX64.h
@@ -58,6 +58,9 @@ public:
     void jmp(Label& label);
     void jmp(OperandX64 op);
 
+    void call(Label& label);
+    void call(OperandX64 op);
+
     // AVX
     void vaddpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
     void vaddps(OperandX64 dst, OperandX64 src1, OperandX64 src2);
diff --git a/CodeGen/src/AssemblyBuilderX64.cpp b/CodeGen/src/AssemblyBuilderX64.cpp
index 27e01781..26347225 100644
--- a/CodeGen/src/AssemblyBuilderX64.cpp
+++ b/CodeGen/src/AssemblyBuilderX64.cpp
@@ -286,11 +286,34 @@ void AssemblyBuilderX64::jmp(OperandX64 op)
     if (logText)
         log("jmp", op);
 
+    placeRex(op);
     place(0xff);
     placeModRegMem(op, 4);
     commit();
 }
 
+void AssemblyBuilderX64::call(Label& label)
+{
+    place(0xe8);
+    placeLabel(label);
+
+    if (logText)
+        log("call", label);
+
+    commit();
+}
+
+void AssemblyBuilderX64::call(OperandX64 op)
+{
+    if (logText)
+        log("call", op);
+
+    placeRex(op);
+    place(0xff);
+    placeModRegMem(op, 2);
+    commit();
+}
+
 void AssemblyBuilderX64::vaddpd(OperandX64 dst, OperandX64 src1, OperandX64 src2)
 {
     placeAvx("vaddpd", dst, src1, src2, 0x58, false, AVX_0F, AVX_66);
diff --git a/Sources.cmake b/Sources.cmake
index f261cba6..44bed8f7 100644
--- a/Sources.cmake
+++ b/Sources.cmake
@@ -247,12 +247,15 @@ if(TARGET Luau.UnitTest)
         tests/IostreamOptional.h
         tests/ScopedFlags.h
         tests/Fixture.cpp
+        tests/AssemblyBuilderX64.test.cpp
         tests/AstQuery.test.cpp
         tests/AstVisitor.test.cpp
         tests/Autocomplete.test.cpp
         tests/BuiltinDefinitions.test.cpp
         tests/Compiler.test.cpp
         tests/Config.test.cpp
+        tests/ConstraintGraphBuilder.test.cpp
+        tests/ConstraintSolver.test.cpp
         tests/CostModel.test.cpp
         tests/Error.test.cpp
         tests/Frontend.test.cpp
@@ -262,8 +265,7 @@ if(TARGET Luau.UnitTest)
         tests/Module.test.cpp
         tests/NonstrictMode.test.cpp
         tests/Normalize.test.cpp
-        tests/ConstraintGraphBuilder.test.cpp
-        tests/ConstraintSolver.test.cpp
+        tests/NotNull.test.cpp
         tests/Parser.test.cpp
         tests/RequireTracer.test.cpp
         tests/RuntimeLimits.test.cpp
@@ -295,11 +297,11 @@ if(TARGET Luau.UnitTest)
         tests/TypeInfer.tryUnify.test.cpp
         tests/TypeInfer.typePacks.cpp
         tests/TypeInfer.unionTypes.test.cpp
+        tests/TypeInfer.unknownnever.test.cpp
         tests/TypePack.test.cpp
         tests/TypeVar.test.cpp
         tests/Variant.test.cpp
         tests/VisitTypeVar.test.cpp
-        tests/AssemblyBuilderX64.test.cpp
         tests/main.cpp)
 endif()
 
diff --git a/VM/src/ltable.cpp b/VM/src/ltable.cpp
index 2316cc3d..79e65919 100644
--- a/VM/src/ltable.cpp
+++ b/VM/src/ltable.cpp
@@ -108,9 +108,9 @@ static LuaNode* hashvec(const Table* t, const float* v)
     memcpy(i, v, sizeof(i));
 
     // convert -0 to 0 to make sure they hash to the same value
-    i[0] = (i[0] == 0x8000000) ? 0 : i[0];
-    i[1] = (i[1] == 0x8000000) ? 0 : i[1];
-    i[2] = (i[2] == 0x8000000) ? 0 : i[2];
+    i[0] = (i[0] == 0x80000000) ? 0 : i[0];
+    i[1] = (i[1] == 0x80000000) ? 0 : i[1];
+    i[2] = (i[2] == 0x80000000) ? 0 : i[2];
 
     // scramble bits to make sure that integer coordinates have entropy in lower bits
     i[0] ^= i[0] >> 17;
@@ -121,7 +121,7 @@ static LuaNode* hashvec(const Table* t, const float* v)
     unsigned int h = (i[0] * 73856093) ^ (i[1] * 19349663) ^ (i[2] * 83492791);
 
 #if LUA_VECTOR_SIZE == 4
-    i[3] = (i[3] == 0x8000000) ? 0 : i[3];
+    i[3] = (i[3] == 0x80000000) ? 0 : i[3];
     i[3] ^= i[3] >> 17;
     h ^= i[3] * 39916801;
 #endif
diff --git a/VM/src/lvmexecute.cpp b/VM/src/lvmexecute.cpp
index 85829ca1..02b39313 100644
--- a/VM/src/lvmexecute.cpp
+++ b/VM/src/lvmexecute.cpp
@@ -640,20 +640,16 @@ static void luau_execute(lua_State* L)
                             VM_PATCH_C(pc - 2, L->cachedslot);
                             VM_NEXT();
                         }
-                        else
-                        {
-                            // slow-path, may invoke Lua calls via __index metamethod
-                            VM_PROTECT(luaV_gettable(L, rb, kv, ra));
-                            VM_NEXT();
-                        }
-                    }
-                    else
-                    {
-                        // slow-path, may invoke Lua calls via __index metamethod
-                        VM_PROTECT(luaV_gettable(L, rb, kv, ra));
-                        VM_NEXT();
+
+                        // fall through to slow path
                     }
+
+                    // fall through to slow path
                 }
+
+                // slow-path, may invoke Lua calls via __index metamethod
+                VM_PROTECT(luaV_gettable(L, rb, kv, ra));
+                VM_NEXT();
             }
 
             VM_CASE(LOP_SETTABLEKS)
@@ -753,19 +749,13 @@ static void luau_execute(lua_State* L)
                         setobj2s(L, ra, &h->array[unsigned(index - 1)]);
                         VM_NEXT();
                     }
-                    else
-                    {
-                        // slow-path: handles out of bounds array lookups and non-integer numeric keys
-                        VM_PROTECT(luaV_gettable(L, rb, rc, ra));
-                        VM_NEXT();
-                    }
-                }
-                else
-                {
-                    // slow-path: handles non-array table lookup as well as __index MT calls
-                    VM_PROTECT(luaV_gettable(L, rb, rc, ra));
-                    VM_NEXT();
+
+                    // fall through to slow path
                 }
+
+                // slow-path: handles out of bounds array lookups, non-integer numeric keys, non-array table lookup, __index MT calls
+                VM_PROTECT(luaV_gettable(L, rb, rc, ra));
+                VM_NEXT();
             }
 
             VM_CASE(LOP_SETTABLE)
@@ -790,19 +780,13 @@ static void luau_execute(lua_State* L)
                         luaC_barriert(L, h, ra);
                         VM_NEXT();
                     }
-                    else
-                    {
-                        // slow-path: handles out of bounds array assignments and non-integer numeric keys
-                        VM_PROTECT(luaV_settable(L, rb, rc, ra));
-                        VM_NEXT();
-                    }
-                }
-                else
-                {
-                    // slow-path: handles non-array table access as well as __newindex MT calls
-                    VM_PROTECT(luaV_settable(L, rb, rc, ra));
-                    VM_NEXT();
+
+                    // fall through to slow path
                 }
+
+                // slow-path: handles out of bounds array assignments, non-integer numeric keys, non-array table access, __newindex MT calls
+                VM_PROTECT(luaV_settable(L, rb, rc, ra));
+                VM_NEXT();
             }
 
             VM_CASE(LOP_GETTABLEN)
@@ -822,6 +806,8 @@ static void luau_execute(lua_State* L)
                         setobj2s(L, ra, &h->array[c]);
                         VM_NEXT();
                     }
+
+                    // fall through to slow path
                 }
 
                 // slow-path: handles out of bounds array lookups
@@ -849,6 +835,8 @@ static void luau_execute(lua_State* L)
                         luaC_barriert(L, h, ra);
                         VM_NEXT();
                     }
+
+                    // fall through to slow path
                 }
 
                 // slow-path: handles out of bounds array lookups
@@ -2176,8 +2164,10 @@ static void luau_execute(lua_State* L)
                 if (!ttisnumber(ra + 0) || !ttisnumber(ra + 1) || !ttisnumber(ra + 2))
                 {
                     // slow-path: can convert arguments to numbers and trigger Lua errors
-                    // Note: this doesn't reallocate stack so we don't need to recompute ra
-                    VM_PROTECT(luau_prepareFORN(L, ra + 0, ra + 1, ra + 2));
+                    // Note: this doesn't reallocate stack so we don't need to recompute ra/base
+                    VM_PROTECT_PC();
+
+                    luau_prepareFORN(L, ra + 0, ra + 1, ra + 2);
                 }
 
                 double limit = nvalue(ra + 0);
diff --git a/bench/bench.py b/bench/bench.py
index e78e96a8..bb3ea5f7 100644
--- a/bench/bench.py
+++ b/bench/bench.py
@@ -101,8 +101,10 @@ def getVmOutput(cmd):
     elif arguments.callgrind:
         try:
             subprocess.check_call("valgrind --tool=callgrind --callgrind-out-file=callgrind.out --combine-dumps=yes --dump-line=no " + cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=scriptdir)
-            file = open(os.path.join(scriptdir, "callgrind.out"), "r")
-            lines = file.readlines()
+            path = os.path.join(scriptdir, "callgrind.out")
+            with open(path, "r") as file:
+                lines = file.readlines()
+            os.unlink(path)
             return getCallgrindOutput(lines)
         except:
             return ""
@@ -402,12 +404,12 @@ def analyzeResult(subdir, main, comparisons):
 
             continue
 
-        pooledStdDev = math.sqrt((main.unbiasedEst + compare.unbiasedEst) / 2)
+        if main.count > 1 and stats:
+            pooledStdDev = math.sqrt((main.unbiasedEst + compare.unbiasedEst) / 2)
 
-        tStat = abs(main.avg - compare.avg) / (pooledStdDev * math.sqrt(2 / main.count))
-        degreesOfFreedom = 2 * main.count - 2
+            tStat = abs(main.avg - compare.avg) / (pooledStdDev * math.sqrt(2 / main.count))
+            degreesOfFreedom = 2 * main.count - 2
 
-        if stats:
             # Two-tailed distribution with 95% conf.
             tCritical = stats.t.ppf(1 - 0.05 / 2, degreesOfFreedom)
 
diff --git a/bench/other/regex.lua b/bench/other/regex.lua
index 270ab3da..eb659a5e 100644
--- a/bench/other/regex.lua
+++ b/bench/other/regex.lua
@@ -2,7 +2,7 @@
 	PCRE2-based RegEx implemention for Luau
 	Version 1.0.0a2
 	BSD 2-Clause Licence
-	Copyright © 2020 - Blockzez (devforum.roblox.com/u/Blockzez and github.com/Blockzez)
+	Copyright © 2020 - Blockzez (devforum /u/Blockzez and github.com/Blockzez)
 	All rights reserved.
 
 	Redistribution and use in source and binary forms, with or without
diff --git a/tests/AssemblyBuilderX64.test.cpp b/tests/AssemblyBuilderX64.test.cpp
index 7f863c6f..15813ae9 100644
--- a/tests/AssemblyBuilderX64.test.cpp
+++ b/tests/AssemblyBuilderX64.test.cpp
@@ -213,6 +213,16 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfLea")
     SINGLE_COMPARE(lea(rax, qword[r13 + r12 * 4 + 4]), 0x4b, 0x8d, 0x44, 0xa5, 0x04);
 }
 
+TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfAbsoluteJumps")
+{
+    SINGLE_COMPARE(jmp(rax), 0x48, 0xff, 0xe0);
+    SINGLE_COMPARE(jmp(r14), 0x49, 0xff, 0xe6);
+    SINGLE_COMPARE(jmp(qword[r14 + rdx * 4]), 0x49, 0xff, 0x24, 0x96);
+    SINGLE_COMPARE(call(rax), 0x48, 0xff, 0xd0);
+    SINGLE_COMPARE(call(r14), 0x49, 0xff, 0xd6);
+    SINGLE_COMPARE(call(qword[r14 + rdx * 4]), 0x49, 0xff, 0x14, 0x96);
+}
+
 TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "ControlFlow")
 {
     // Jump back
@@ -260,6 +270,23 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "ControlFlow")
         {0xe9, 0x04, 0x00, 0x00, 0x00, 0x48, 0x83, 0xe7, 0x3e});
 }
 
+TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "LabelCall")
+{
+    check(
+        [](AssemblyBuilderX64& build) {
+            Label fnB;
+
+            build.and_(rcx, 0x3e);
+            build.call(fnB);
+            build.ret();
+
+            build.setLabel(fnB);
+            build.lea(rax, qword[rcx + 0x1f]);
+            build.ret();
+        },
+        {0x48, 0x83, 0xe1, 0x3e, 0xe8, 0x01, 0x00, 0x00, 0x00, 0xc3, 0x48, 0x8d, 0x41, 0x1f, 0xc3});
+}
+
 TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXBinaryInstructionForms")
 {
     SINGLE_COMPARE(vaddpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0xa9, 0x58, 0xc6);
diff --git a/tests/AstQuery.test.cpp b/tests/AstQuery.test.cpp
index f0017509..6ec1426c 100644
--- a/tests/AstQuery.test.cpp
+++ b/tests/AstQuery.test.cpp
@@ -105,4 +105,37 @@ if true then
     REQUIRE(parentStat->is<AstStatIf>());
 }
 
+TEST_CASE_FIXTURE(Fixture, "ac_ast_ancestry_at_number_const")
+{
+    check(R"(
+print(3.)
+    )");
+
+    std::vector<AstNode*> ancestry = findAncestryAtPositionForAutocomplete(*getMainSourceModule(), Position(1, 8));
+    REQUIRE_GE(ancestry.size(), 2);
+    REQUIRE(ancestry.back()->is<AstExprConstantNumber>());
+}
+
+TEST_CASE_FIXTURE(Fixture, "ac_ast_ancestry_in_workspace_dot")
+{
+    check(R"(
+print(workspace.)
+    )");
+
+    std::vector<AstNode*> ancestry = findAncestryAtPositionForAutocomplete(*getMainSourceModule(), Position(1, 16));
+    REQUIRE_GE(ancestry.size(), 2);
+    REQUIRE(ancestry.back()->is<AstExprIndexName>());
+}
+
+TEST_CASE_FIXTURE(Fixture, "ac_ast_ancestry_in_workspace_colon")
+{
+    check(R"(
+print(workspace:)
+    )");
+
+    std::vector<AstNode*> ancestry = findAncestryAtPositionForAutocomplete(*getMainSourceModule(), Position(1, 16));
+    REQUIRE_GE(ancestry.size(), 2);
+    REQUIRE(ancestry.back()->is<AstExprIndexName>());
+}
+
 TEST_SUITE_END();
diff --git a/tests/Fixture.h b/tests/Fixture.h
index 1bc573da..4bd6f1ea 100644
--- a/tests/Fixture.h
+++ b/tests/Fixture.h
@@ -128,6 +128,7 @@ struct Fixture
     std::optional<TypeId> lookupImportedType(const std::string& moduleAlias, const std::string& name);
 
     ScopedFastFlag sff_DebugLuauFreezeArena;
+    ScopedFastFlag sff_UnknownNever{"LuauUnknownAndNeverType", true};
 
     TestFileResolver fileResolver;
     TestConfigResolver configResolver;
diff --git a/tests/Module.test.cpp b/tests/Module.test.cpp
index 7c2f4d1c..dd94e9d7 100644
--- a/tests/Module.test.cpp
+++ b/tests/Module.test.cpp
@@ -301,8 +301,6 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
 
 TEST_CASE_FIXTURE(Fixture, "any_persistance_does_not_leak")
 {
-    ScopedFastFlag luauNonCopyableTypeVarFields{"LuauNonCopyableTypeVarFields", true};
-
     fileResolver.source["Module/A"] = R"(
 export type A = B
 type B = A
diff --git a/tests/Normalize.test.cpp b/tests/Normalize.test.cpp
index a474b6e7..fb0a899e 100644
--- a/tests/Normalize.test.cpp
+++ b/tests/Normalize.test.cpp
@@ -1055,8 +1055,6 @@ export type t1 = { a: typeof(string.byte) }
 
 TEST_CASE_FIXTURE(Fixture, "intersection_combine_on_bound_self")
 {
-    ScopedFastFlag luauNormalizeCombineEqFix{"LuauNormalizeCombineEqFix", true};
-
     CheckResult result = check(R"(
 export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))
     )");
@@ -1064,6 +1062,46 @@ export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t
     LUAU_REQUIRE_ERRORS(result);
 }
 
+TEST_CASE_FIXTURE(Fixture, "normalize_unions_containing_never")
+{
+    ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
+
+    CheckResult result = check(R"(
+        type Foo = string | never
+        local foo: Foo
+    )");
+
+    CHECK_EQ("string", toString(requireType("foo")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "normalize_unions_containing_unknown")
+{
+    ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
+
+    CheckResult result = check(R"(
+        type Foo = string | unknown
+        local foo: Foo
+    )");
+
+    CHECK_EQ("unknown", toString(requireType("foo")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "any_wins_the_battle_over_unknown_in_unions")
+{
+    ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
+
+    CheckResult result = check(R"(
+        type Foo = unknown | any
+        local foo: Foo
+
+        type Bar = any | unknown
+        local bar: Bar
+    )");
+
+    CHECK_EQ("any", toString(requireType("foo")));
+    CHECK_EQ("any", toString(requireType("bar")));
+}
+
 TEST_CASE_FIXTURE(BuiltinsFixture, "normalization_does_not_convert_ever")
 {
     ScopedFastFlag sff[]{
diff --git a/tests/Parser.test.cpp b/tests/Parser.test.cpp
index c3c75998..c517853f 100644
--- a/tests/Parser.test.cpp
+++ b/tests/Parser.test.cpp
@@ -2648,7 +2648,6 @@ type Z<T> = { a: string | T..., b: number }
 
 TEST_CASE_FIXTURE(Fixture, "recover_function_return_type_annotations")
 {
-    ScopedFastFlag sff{"LuauReturnTypeTokenConfusion", true};
     ParseResult result = tryParse(R"(
 type Custom<A, B, C> = { x: A, y: B, z: C }
 type Packed<A...> = { x: (A...) -> () }
diff --git a/tests/ToString.test.cpp b/tests/ToString.test.cpp
index 1601a152..52a29bcc 100644
--- a/tests/ToString.test.cpp
+++ b/tests/ToString.test.cpp
@@ -499,7 +499,7 @@ local function target(callback: nil) return callback(4, "hello") end
     )");
 
     LUAU_REQUIRE_ERRORS(result);
-    CHECK_EQ("(nil) -> (*unknown*)", toString(requireType("target")));
+    CHECK_EQ("(nil) -> (<error-type>)", toString(requireType("target")));
 }
 
 TEST_CASE_FIXTURE(Fixture, "toStringGenericPack")
diff --git a/tests/TypeInfer.anyerror.test.cpp b/tests/TypeInfer.anyerror.test.cpp
index bc55940e..4c5309e0 100644
--- a/tests/TypeInfer.anyerror.test.cpp
+++ b/tests/TypeInfer.anyerror.test.cpp
@@ -94,7 +94,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error")
 
     LUAU_REQUIRE_ERROR_COUNT(1, result);
 
-    CHECK_EQ("*unknown*", toString(requireType("a")));
+    CHECK_EQ("<error-type>", toString(requireType("a")));
 }
 
 TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2")
@@ -110,7 +110,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2")
 
     LUAU_REQUIRE_ERROR_COUNT(1, result);
 
-    CHECK_EQ("*unknown*", toString(requireType("a")));
+    CHECK_EQ("<error-type>", toString(requireType("a")));
 }
 
 TEST_CASE_FIXTURE(Fixture, "length_of_error_type_does_not_produce_an_error")
@@ -225,7 +225,7 @@ TEST_CASE_FIXTURE(Fixture, "calling_error_type_yields_error")
 
     CHECK_EQ("unknown", err->name);
 
-    CHECK_EQ("*unknown*", toString(requireType("a")));
+    CHECK_EQ("<error-type>", toString(requireType("a")));
 }
 
 TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error")
@@ -234,7 +234,7 @@ TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error")
         local a = Utility.Create "Foo" {}
     )");
 
-    CHECK_EQ("*unknown*", toString(requireType("a")));
+    CHECK_EQ("<error-type>", toString(requireType("a")));
 }
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_complex_function_with_any")
diff --git a/tests/TypeInfer.builtins.test.cpp b/tests/TypeInfer.builtins.test.cpp
index 2f0266ec..7d1bd6ba 100644
--- a/tests/TypeInfer.builtins.test.cpp
+++ b/tests/TypeInfer.builtins.test.cpp
@@ -925,7 +925,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_returns_false_and_string_iff_it_knows
     )");
 
     LUAU_REQUIRE_NO_ERRORS(result);
-    CHECK_EQ("(nil) -> nil", toString(requireType("f")));
+    CHECK_EQ("(nil) -> (never, ...never)", toString(requireType("f")));
 }
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
@@ -952,7 +952,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
     CHECK_EQ("number", toString(requireType("a")));
     CHECK_EQ("string", toString(requireType("b")));
     CHECK_EQ("boolean", toString(requireType("c")));
-    CHECK_EQ("*unknown*", toString(requireType("d")));
+    CHECK_EQ("<error-type>", toString(requireType("d")));
 }
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments")
@@ -965,8 +965,8 @@ a:b()
 a:b({})
     )");
     LUAU_REQUIRE_ERROR_COUNT(2, result);
-    CHECK_EQ(result.errors[0], (TypeError{Location{{2, 0}, {2, 5}}, CountMismatch{2, 0}}));
-    CHECK_EQ(result.errors[1], (TypeError{Location{{3, 0}, {3, 5}}, CountMismatch{2, 1}}));
+    CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function expects 2 arguments, but none are specified");
+    CHECK_EQ(toString(result.errors[1]), "Argument count mismatch. Function expects 2 arguments, but only 1 is specified");
 }
 
 TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function")
@@ -1008,4 +1008,139 @@ end
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types")
+{
+    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
+    CheckResult result = check(R"END(
+        local a, b, c = string.gmatch("This is a string", "(.()(%a+))")()
+    )END");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ(toString(requireType("a")), "string");
+    CHECK_EQ(toString(requireType("b")), "number");
+    CHECK_EQ(toString(requireType("c")), "string");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types2")
+{
+    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
+    CheckResult result = check(R"END(
+        local a, b, c = ("This is a string"):gmatch("(.()(%a+))")()
+    )END");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ(toString(requireType("a")), "string");
+    CHECK_EQ(toString(requireType("b")), "number");
+    CHECK_EQ(toString(requireType("c")), "string");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_default_capture")
+{
+    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
+    CheckResult result = check(R"END(
+        local a, b, c, d = string.gmatch("T(his)() is a string", ".")()
+    )END");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+
+    CountMismatch* acm = get<CountMismatch>(result.errors[0]);
+    REQUIRE(acm);
+    CHECK_EQ(acm->context, CountMismatch::Result);
+    CHECK_EQ(acm->expected, 1);
+    CHECK_EQ(acm->actual, 4);
+
+    CHECK_EQ(toString(requireType("a")), "string");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_balanced_escaped_parens")
+{
+    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
+    CheckResult result = check(R"END(
+        local a, b, c, d = string.gmatch("T(his) is a string", "((.)%b()())")()
+    )END");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+
+    CountMismatch* acm = get<CountMismatch>(result.errors[0]);
+    REQUIRE(acm);
+    CHECK_EQ(acm->context, CountMismatch::Result);
+    CHECK_EQ(acm->expected, 3);
+    CHECK_EQ(acm->actual, 4);
+
+    CHECK_EQ(toString(requireType("a")), "string");
+    CHECK_EQ(toString(requireType("b")), "string");
+    CHECK_EQ(toString(requireType("c")), "number");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_parens_in_sets_are_ignored")
+{
+    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
+    CheckResult result = check(R"END(
+        local a, b, c = string.gmatch("T(his)() is a string", "(T[()])()")()
+    )END");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+
+    CountMismatch* acm = get<CountMismatch>(result.errors[0]);
+    REQUIRE(acm);
+    CHECK_EQ(acm->context, CountMismatch::Result);
+    CHECK_EQ(acm->expected, 2);
+    CHECK_EQ(acm->actual, 3);
+
+    CHECK_EQ(toString(requireType("a")), "string");
+    CHECK_EQ(toString(requireType("b")), "number");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_set_containing_lbracket")
+{
+    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
+    CheckResult result = check(R"END(
+        local a, b = string.gmatch("[[[", "()([[])")()
+    )END");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ(toString(requireType("a")), "number");
+    CHECK_EQ(toString(requireType("b")), "string");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_leading_end_bracket_is_part_of_set")
+{
+    CheckResult result = check(R"END(
+        -- An immediate right-bracket following a left-bracket is included within the set;
+        -- thus, '[]]'' is the set containing ']', and '[]' is an invalid set missing an enclosing
+        -- right-bracket. We detect an invalid set in this case and fall back to to default gmatch
+        -- typing.
+        local foo = string.gmatch("T[hi%]s]]]() is a string", "([]s)")
+    )END");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ(toString(requireType("foo")), "() -> (...string)");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_invalid_pattern_fallback_to_builtin")
+{
+    CheckResult result = check(R"END(
+        local foo = string.gmatch("T(his)() is a string", ")")
+    )END");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ(toString(requireType("foo")), "() -> (...string)");
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_invalid_pattern_fallback_to_builtin2")
+{
+    CheckResult result = check(R"END(
+        local foo = string.gmatch("T(his)() is a string", "[")
+    )END");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ(toString(requireType("foo")), "() -> (...string)");
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.functions.test.cpp b/tests/TypeInfer.functions.test.cpp
index 401a6c64..6e6549d3 100644
--- a/tests/TypeInfer.functions.test.cpp
+++ b/tests/TypeInfer.functions.test.cpp
@@ -916,13 +916,13 @@ TEST_CASE_FIXTURE(Fixture, "function_cast_error_uses_correct_language")
     REQUIRE(tm1);
 
     CHECK_EQ("(string) -> number", toString(tm1->wantedType));
-    CHECK_EQ("(string, *unknown*) -> number", toString(tm1->givenType));
+    CHECK_EQ("(string, <error-type>) -> number", toString(tm1->givenType));
 
     auto tm2 = get<TypeMismatch>(result.errors[1]);
     REQUIRE(tm2);
 
     CHECK_EQ("(number, number) -> (number, number)", toString(tm2->wantedType));
-    CHECK_EQ("(string, *unknown*) -> number", toString(tm2->givenType));
+    CHECK_EQ("(string, <error-type>) -> number", toString(tm2->givenType));
 }
 
 TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type")
@@ -1535,7 +1535,7 @@ function t:b() return 2 end -- not OK
     )");
 
     LUAU_REQUIRE_ERROR_COUNT(1, result);
-    CHECK_EQ(R"(Type '(*unknown*) -> number' could not be converted into '() -> number'
+    CHECK_EQ(R"(Type '(<error-type>) -> number' could not be converted into '() -> number'
 caused by:
   Argument count mismatch. Function expects 1 argument, but none are specified)",
         toString(result.errors[0]));
@@ -1692,4 +1692,52 @@ TEST_CASE_FIXTURE(Fixture, "call_o_with_another_argument_after_foo_was_quantifie
     // TODO: check the normalized type of f
 }
 
+TEST_CASE_FIXTURE(Fixture, "free_is_not_bound_to_unknown")
+{
+    CheckResult result = check(R"(
+        local function foo(f: (unknown) -> (), x)
+            f(x)
+        end
+    )");
+
+    CHECK_EQ("<a>((unknown) -> (), a) -> ()", toString(requireType("foo")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "dont_infer_parameter_types_for_functions_from_their_call_site")
+{
+    CheckResult result = check(R"(
+        local t = {}
+
+        function t.f(x)
+            return x
+        end
+
+        t.__index = t
+
+        function g(s)
+            local q = s.p and s.p.q or nil
+            return q and t.f(q) or nil
+        end
+
+        local f = t.f
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("<a>(a) -> a", toString(requireType("f")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "dont_mutate_the_underlying_head_of_typepack_when_calling_with_self")
+{
+    CheckResult result = check(R"(
+        local t = {}
+        function t:m(x) end
+        function f(): never return 5 :: never end
+        t:m(f())
+        t:m(f())
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.generics.test.cpp b/tests/TypeInfer.generics.test.cpp
index e9e94cfb..46258072 100644
--- a/tests/TypeInfer.generics.test.cpp
+++ b/tests/TypeInfer.generics.test.cpp
@@ -9,6 +9,8 @@
 
 #include "doctest.h"
 
+LUAU_FASTFLAG(LuauCheckGenericHOFTypes)
+
 using namespace Luau;
 
 TEST_SUITE_BEGIN("GenericsTests");
@@ -1001,7 +1003,7 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_quantifying")
 
     std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType("t0");
     REQUIRE(t0);
-    CHECK_EQ("*unknown*", toString(t0->type));
+    CHECK_EQ("<error-type>", toString(t0->type));
 
     auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
         return get<OccursCheckFailed>(err);
@@ -1095,10 +1097,18 @@ local b = sumrec(sum) -- ok
 local c = sumrec(function(x, y, f) return f(x, y) end) -- type binders are not inferred
     )");
 
-    LUAU_REQUIRE_ERRORS(result);
-    CHECK_EQ("Type '(a, b, (a, b) -> (c...)) -> (c...)' could not be converted into '<a>(a, a, (a, a) -> a) -> a'; different number of generic type "
-             "parameters",
-        toString(result.errors[0]));
+    if (FFlag::LuauCheckGenericHOFTypes)
+    {
+        LUAU_REQUIRE_NO_ERRORS(result);
+    }
+    else
+    {
+        LUAU_REQUIRE_ERRORS(result);
+        CHECK_EQ(
+            "Type '(a, b, (a, b) -> (c...)) -> (c...)' could not be converted into '<a>(a, a, (a, a) -> a) -> a'; different number of generic type "
+            "parameters",
+            toString(result.errors[0]));
+    }
 }
 
 TEST_CASE_FIXTURE(Fixture, "substitution_with_bound_table")
@@ -1185,4 +1195,23 @@ TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_gen
     CHECK("<X, a...>((X) -> (a...), X) -> (a...)" == toString(requireType("foo")));
 }
 
+TEST_CASE_FIXTURE(Fixture, "do_not_always_instantiate_generic_intersection_types")
+{
+    ScopedFastFlag sff[] = {
+        {"LuauMaybeGenericIntersectionTypes", true},
+    };
+
+    CheckResult result = check(R"(
+        --!strict
+        type Array<T> = { [number]: T }
+
+        type Array_Statics = {
+            new: <T>() -> Array<T>,
+        }
+
+        local _Arr : Array<any> & Array_Statics = {} :: Array_Statics
+    )");
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.loops.test.cpp b/tests/TypeInfer.loops.test.cpp
index 1c6fe1d8..56b807f8 100644
--- a/tests/TypeInfer.loops.test.cpp
+++ b/tests/TypeInfer.loops.test.cpp
@@ -142,7 +142,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
     CHECK_EQ(2, result.errors.size());
 
     TypeId p = requireType("p");
-    CHECK_EQ("*unknown*", toString(p));
+    CHECK_EQ("<error-type>", toString(p));
 }
 
 TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function")
diff --git a/tests/TypeInfer.modules.test.cpp b/tests/TypeInfer.modules.test.cpp
index a0f670f1..2343a7fa 100644
--- a/tests/TypeInfer.modules.test.cpp
+++ b/tests/TypeInfer.modules.test.cpp
@@ -143,7 +143,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_module_that_does_not_export")
 
     auto hootyType = requireType(bModule, "Hooty");
 
-    CHECK_EQ("*unknown*", toString(hootyType));
+    CHECK_EQ("<error-type>", toString(hootyType));
 }
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "warn_if_you_try_to_require_a_non_modulescript")
@@ -244,7 +244,7 @@ local ModuleA = require(game.A)
     LUAU_REQUIRE_NO_ERRORS(result);
 
     std::optional<TypeId> oty = requireType("ModuleA");
-    CHECK_EQ("*unknown*", toString(*oty));
+    CHECK_EQ("<error-type>", toString(*oty));
 }
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types")
@@ -302,6 +302,30 @@ type Rename = typeof(x.x)
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_4")
+{
+    fileResolver.source["game/A"] = R"(
+export type Array<T> = {T}
+local arrayops = {}
+function arrayops.foo(x: Array<any>) end
+return arrayops
+    )";
+
+    CheckResult result = check(R"(
+local arrayops = require(game.A)
+
+local tbl = {}
+tbl.a = 2
+function tbl:foo(b: number, c: number)
+    -- introduce BoundTypeVar to imported type
+    arrayops.foo(self._regions)
+end
+type Table = typeof(tbl)
+)");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
 TEST_CASE_FIXTURE(BuiltinsFixture, "module_type_conflict")
 {
     fileResolver.source["game/A"] = R"(
@@ -363,4 +387,21 @@ caused by:
   Property 'x' is not compatible. Type 'number' could not be converted into 'string')");
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_anyification_clone_immutable_types")
+{
+    ScopedFastFlag luauAnyificationMustClone{"LuauAnyificationMustClone", true};
+
+    fileResolver.source["game/A"] = R"(
+return function(...) end
+    )";
+
+    fileResolver.source["game/B"] = R"(
+local l0 = require(game.A)
+return l0
+    )";
+
+    CheckResult result = frontend.check("game/B");
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.operators.test.cpp b/tests/TypeInfer.operators.test.cpp
index e6174df2..c90f0a4d 100644
--- a/tests/TypeInfer.operators.test.cpp
+++ b/tests/TypeInfer.operators.test.cpp
@@ -871,4 +871,26 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "equality_operations_succeed_if_any_union_bra
     CHECK(toString(result2.errors[0]) == "Types Foo and Bar cannot be compared with == because they do not have the same metatable");
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "expected_types_through_binary_and")
+{
+    ScopedFastFlag sff{"LuauBinaryNeedsExpectedTypesToo", true};
+
+    CheckResult result = check(R"(
+        local x: "a" | "b" | boolean = math.random() > 0.5 and "a"
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "expected_types_through_binary_or")
+{
+    ScopedFastFlag sff{"LuauBinaryNeedsExpectedTypesToo", true};
+
+    CheckResult result = check(R"(
+        local x: "a" | "b" | boolean = math.random() > 0.5 or "b"
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.primitives.test.cpp b/tests/TypeInfer.primitives.test.cpp
index e1684df7..9e8e2503 100644
--- a/tests/TypeInfer.primitives.test.cpp
+++ b/tests/TypeInfer.primitives.test.cpp
@@ -47,7 +47,7 @@ TEST_CASE_FIXTURE(Fixture, "string_index")
     REQUIRE(nat);
     CHECK_EQ("string", toString(nat->ty));
 
-    CHECK_EQ("*unknown*", toString(requireType("t")));
+    CHECK_EQ("<error-type>", toString(requireType("t")));
 }
 
 TEST_CASE_FIXTURE(Fixture, "string_method")
diff --git a/tests/TypeInfer.provisional.test.cpp b/tests/TypeInfer.provisional.test.cpp
index 018059fd..dc686890 100644
--- a/tests/TypeInfer.provisional.test.cpp
+++ b/tests/TypeInfer.provisional.test.cpp
@@ -225,7 +225,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_x_not_equal_to_nil")
     CHECK_EQ("{| x: nil, y: nil |} | {| x: string, y: number |}", toString(requireTypeAtPosition({7, 28})));
 }
 
-TEST_CASE_FIXTURE(Fixture, "bail_early_if_unification_is_too_complicated" * doctest::timeout(0.5))
+TEST_CASE_FIXTURE(BuiltinsFixture, "bail_early_if_unification_is_too_complicated" * doctest::timeout(0.5))
 {
     ScopedFastInt sffi{"LuauTarjanChildLimit", 1};
     ScopedFastInt sffi2{"LuauTypeInferIterationLimit", 1};
@@ -499,6 +499,17 @@ TEST_CASE_FIXTURE(Fixture, "constrained_is_level_dependent")
     CHECK_EQ("<a...>(t1) -> {| [t1]: boolean |} where t1 = t2 ; t2 = {+ m1: (t1) -> (a...), m2: (t2) -> (b...) +}", toString(requireType("f")));
 }
 
+TEST_CASE_FIXTURE(Fixture, "free_is_not_bound_to_any")
+{
+    CheckResult result = check(R"(
+        local function foo(f: (any) -> (), x)
+            f(x)
+        end
+    )");
+
+    CHECK_EQ("((any) -> (), any) -> ()", toString(requireType("foo")));
+}
+
 TEST_CASE_FIXTURE(BuiltinsFixture, "greedy_inference_with_shared_self_triggers_function_with_no_returns")
 {
     ScopedFastFlag sff{"DebugLuauSharedSelf", true};
diff --git a/tests/TypeInfer.refinements.test.cpp b/tests/TypeInfer.refinements.test.cpp
index 3f5dad3d..cc8cdee3 100644
--- a/tests/TypeInfer.refinements.test.cpp
+++ b/tests/TypeInfer.refinements.test.cpp
@@ -272,8 +272,8 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_only_look_up_types_from_global_scope")
 
     LUAU_REQUIRE_NO_ERRORS(result);
 
-    CHECK_EQ("*unknown*", toString(requireTypeAtPosition({8, 44})));
-    CHECK_EQ("*unknown*", toString(requireTypeAtPosition({9, 38})));
+    CHECK_EQ("never", toString(requireTypeAtPosition({8, 44})));
+    CHECK_EQ("never", toString(requireTypeAtPosition({9, 38})));
 }
 
 TEST_CASE_FIXTURE(Fixture, "call_a_more_specific_function_using_typeguard")
@@ -526,7 +526,7 @@ TEST_CASE_FIXTURE(Fixture, "type_narrow_to_vector")
 
     LUAU_REQUIRE_NO_ERRORS(result);
 
-    CHECK_EQ("*unknown*", toString(requireTypeAtPosition({3, 28})));
+    CHECK_EQ("<error-type>", toString(requireTypeAtPosition({3, 28})));
 }
 
 TEST_CASE_FIXTURE(Fixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true")
@@ -651,7 +651,7 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_overloaded_function")
     CHECK_EQ("nil", toString(requireTypeAtPosition({6, 28})));
 }
 
-TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_warns_on_no_overlapping_types_only_when_sense_is_true")
+TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_narrowed_into_nothingness")
 {
     CheckResult result = check(R"(
         local function f(t: {x: number})
@@ -666,7 +666,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_warns_on_no_overlapping_types_onl
 
     LUAU_REQUIRE_NO_ERRORS(result);
 
-    CHECK_EQ("*unknown*", toString(requireTypeAtPosition({3, 28})));
+    CHECK_EQ("never", toString(requireTypeAtPosition({3, 28})));
 }
 
 TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b")
@@ -1074,7 +1074,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_free_table_to_vector")
 
     CHECK_EQ("Vector3", toString(requireTypeAtPosition({5, 28}))); // type(vec) == "vector"
 
-    CHECK_EQ("*unknown*", toString(requireTypeAtPosition({7, 28}))); // typeof(vec) == "Instance"
+    CHECK_EQ("never", toString(requireTypeAtPosition({7, 28}))); // typeof(vec) == "Instance"
 
     CHECK_EQ("{+ X: a, Y: b, Z: c +}", toString(requireTypeAtPosition({9, 28}))); // type(vec) ~= "vector" and typeof(vec) ~= "Instance"
 }
@@ -1206,6 +1206,24 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_doesnt_leak_to_elseif")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknowns")
+{
+    CheckResult result = check(R"(
+        local function f(x: unknown)
+            if type(x) == "string" then
+                local foo = x
+            else
+                local bar = x
+            end
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("string", toString(requireTypeAtPosition({3, 28})));
+    CHECK_EQ("unknown", toString(requireTypeAtPosition({5, 28})));
+}
+
 TEST_CASE_FIXTURE(BuiltinsFixture, "falsiness_of_TruthyPredicate_narrows_into_nil")
 {
     ScopedFastFlag sff{"LuauFalsyPredicateReturnsNilInstead", true};
@@ -1227,4 +1245,19 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "falsiness_of_TruthyPredicate_narrows_into_ni
     CHECK_EQ("number", toString(requireTypeAtPosition({6, 28})));
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "what_nonsensical_condition")
+{
+    CheckResult result = check(R"(
+        local function f(x)
+            if type(x) == "string" and type(x) == "number" then
+                local foo = x
+            end
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireTypeAtPosition({3, 28})));
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.tables.test.cpp b/tests/TypeInfer.tables.test.cpp
index eead5b30..3e830f2a 100644
--- a/tests/TypeInfer.tables.test.cpp
+++ b/tests/TypeInfer.tables.test.cpp
@@ -3070,4 +3070,18 @@ TEST_CASE_FIXTURE(Fixture, "quantify_even_that_table_was_never_exported_at_all")
     CHECK_EQ("{| m: <a, b>({+ x: a, y: b +}) -> a, n: <a, b>({+ x: a, y: b +}) -> b |}", toString(requireType("T"), opts));
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "leaking_bad_metatable_errors")
+{
+    ScopedFastFlag luauIndexSilenceErrors{"LuauIndexSilenceErrors", true};
+
+    CheckResult result = check(R"(
+local a = setmetatable({}, 1)
+local b = a.x
+    )");
+
+    LUAU_REQUIRE_ERROR_COUNT(2, result);
+    CHECK_EQ("Metatable was not a table", toString(result.errors[0]));
+    CHECK_EQ("Type 'a' does not have key 'x'", toString(result.errors[1]));
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.test.cpp b/tests/TypeInfer.test.cpp
index a175b826..7d1fb56b 100644
--- a/tests/TypeInfer.test.cpp
+++ b/tests/TypeInfer.test.cpp
@@ -238,10 +238,10 @@ TEST_CASE_FIXTURE(Fixture, "type_errors_infer_types")
     // TODO: Should we assert anything about these tests when DCR is being used?
     if (!FFlag::DebugLuauDeferredConstraintResolution)
     {
-        CHECK_EQ("*unknown*", toString(requireType("c")));
-        CHECK_EQ("*unknown*", toString(requireType("d")));
-        CHECK_EQ("*unknown*", toString(requireType("e")));
-        CHECK_EQ("*unknown*", toString(requireType("f")));
+        CHECK_EQ("<error-type>", toString(requireType("c")));
+        CHECK_EQ("<error-type>", toString(requireType("d")));
+        CHECK_EQ("<error-type>", toString(requireType("e")));
+        CHECK_EQ("<error-type>", toString(requireType("f")));
     }
 }
 
@@ -622,7 +622,7 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_isoptional")
 
     std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType("t0");
     REQUIRE(t0);
-    CHECK_EQ("*unknown*", toString(t0->type));
+    CHECK_EQ("<error-type>", toString(t0->type));
 
     auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
         return get<OccursCheckFailed>(err);
diff --git a/tests/TypeInfer.tryUnify.test.cpp b/tests/TypeInfer.tryUnify.test.cpp
index 49deae71..d51a38f8 100644
--- a/tests/TypeInfer.tryUnify.test.cpp
+++ b/tests/TypeInfer.tryUnify.test.cpp
@@ -121,7 +121,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "members_of_failed_typepack_unification_are_u
     LUAU_REQUIRE_ERROR_COUNT(1, result);
 
     CHECK_EQ("a", toString(requireType("a")));
-    CHECK_EQ("*unknown*", toString(requireType("b")));
+    CHECK_EQ("<error-type>", toString(requireType("b")));
 }
 
 TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_constrained")
@@ -136,7 +136,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_con
     LUAU_REQUIRE_ERROR_COUNT(1, result);
 
     CHECK_EQ("a", toString(requireType("a")));
-    CHECK_EQ("*unknown*", toString(requireType("b")));
+    CHECK_EQ("<error-type>", toString(requireType("b")));
     CHECK_EQ("number", toString(requireType("c")));
 }
 
diff --git a/tests/TypeInfer.unionTypes.test.cpp b/tests/TypeInfer.unionTypes.test.cpp
index 2b48133d..94918692 100644
--- a/tests/TypeInfer.unionTypes.test.cpp
+++ b/tests/TypeInfer.unionTypes.test.cpp
@@ -199,7 +199,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_missing_property")
     CHECK_EQ(mup->missing[0], *bTy);
     CHECK_EQ(mup->key, "x");
 
-    CHECK_EQ("*unknown*", toString(requireType("r")));
+    CHECK_EQ("<error-type>", toString(requireType("r")));
 }
 
 TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_one_property_of_type_any")
diff --git a/tests/TypeInfer.unknownnever.test.cpp b/tests/TypeInfer.unknownnever.test.cpp
new file mode 100644
index 00000000..bc742b03
--- /dev/null
+++ b/tests/TypeInfer.unknownnever.test.cpp
@@ -0,0 +1,280 @@
+// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
+
+#include "Fixture.h"
+
+#include "doctest.h"
+
+using namespace Luau;
+
+TEST_SUITE_BEGIN("TypeInferUnknownNever");
+
+TEST_CASE_FIXTURE(Fixture, "string_subtype_and_unknown_supertype")
+{
+    CheckResult result = check(R"(
+        local function f(x: string)
+            local foo: unknown = x
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "unknown_subtype_and_string_supertype")
+{
+    CheckResult result = check(R"(
+        local function f(x: unknown)
+            local foo: string = x
+        end
+    )");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "unknown_is_reflexive")
+{
+    CheckResult result = check(R"(
+        local function f(x: unknown)
+            local foo: unknown = x
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "string_subtype_and_never_supertype")
+{
+    CheckResult result = check(R"(
+        local function f(x: string)
+            local foo: never = x
+        end
+    )");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "never_subtype_and_string_supertype")
+{
+    CheckResult result = check(R"(
+        local function f(x: never)
+            local foo: string = x
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "never_is_reflexive")
+{
+    CheckResult result = check(R"(
+        local function f(x: never)
+            local foo: never = x
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "unknown_is_optional_because_it_too_encompasses_nil")
+{
+    CheckResult result = check(R"(
+        local t: {x: unknown} = {}
+    )");
+}
+
+TEST_CASE_FIXTURE(Fixture, "table_with_prop_of_type_never_is_uninhabitable")
+{
+    CheckResult result = check(R"(
+        local t: {x: never} = {}
+    )");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "table_with_prop_of_type_never_is_also_reflexive")
+{
+    CheckResult result = check(R"(
+        local t: {x: never} = {x = 5 :: never}
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "array_like_table_of_never_is_inhabitable")
+{
+    CheckResult result = check(R"(
+        local t: {never} = {}
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "type_packs_containing_never_is_itself_uninhabitable")
+{
+    CheckResult result = check(R"(
+        local function f() return "foo", 5 :: never end
+
+        local x, y, z = f()
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireType("x")));
+    CHECK_EQ("never", toString(requireType("y")));
+    CHECK_EQ("never", toString(requireType("z")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "type_packs_containing_never_is_itself_uninhabitable2")
+{
+    CheckResult result = check(R"(
+        local function f(): (string, never) return "", 5 :: never end
+        local function g(): (never, string) return 5 :: never, "" end
+
+        local x1, x2 = f()
+        local y1, y2 = g()
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireType("x1")));
+    CHECK_EQ("never", toString(requireType("x2")));
+    CHECK_EQ("never", toString(requireType("y1")));
+    CHECK_EQ("never", toString(requireType("y2")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "index_on_never")
+{
+    CheckResult result = check(R"(
+        local x: never = 5 :: never
+        local z = x.y
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireType("z")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "call_never")
+{
+    CheckResult result = check(R"(
+        local f: never = 5 :: never
+        local x, y, z = f()
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireType("x")));
+    CHECK_EQ("never", toString(requireType("y")));
+    CHECK_EQ("never", toString(requireType("z")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "assign_to_local_which_is_never")
+{
+    CheckResult result = check(R"(
+        local t: never
+        t = 3
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "assign_to_global_which_is_never")
+{
+    CheckResult result = check(R"(
+        --!nonstrict
+        t = 5 :: never
+        t = ""
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "assign_to_prop_which_is_never")
+{
+    CheckResult result = check(R"(
+        local t: never
+        t.x = 5
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "assign_to_subscript_which_is_never")
+{
+    CheckResult result = check(R"(
+        local t: never
+        t[5] = 7
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "assign_to_subscript_which_is_never")
+{
+    CheckResult result = check(R"(
+        for i, v in (5 :: never) do
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "pick_never_from_variadic_type_pack")
+{
+    CheckResult result = check(R"(
+        local function f(...: never)
+            local x, y = (...)
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
+TEST_CASE_FIXTURE(Fixture, "index_on_union_of_tables_for_properties_that_is_never")
+{
+    CheckResult result = check(R"(
+        type Disjoint = {foo: never, bar: unknown, tag: "ok"} | {foo: never, baz: unknown, tag: "err"}
+        local disjoint: Disjoint = {foo = 5 :: never, bar = true, tag = "ok"}
+        local foo = disjoint.foo
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireType("foo")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "index_on_union_of_tables_for_properties_that_is_sorta_never")
+{
+    CheckResult result = check(R"(
+        type Disjoint = {foo: string, bar: unknown, tag: "ok"} | {foo: never, baz: unknown, tag: "err"}
+        local disjoint: Disjoint = {foo = 5 :: never, bar = true, tag = "ok"}
+        local foo = disjoint.foo
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("string", toString(requireType("foo")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "unary_minus_of_never")
+{
+    CheckResult result = check(R"(
+        local x = -(5 :: never)
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireType("x")));
+}
+
+TEST_CASE_FIXTURE(Fixture, "length_of_never")
+{
+    CheckResult result = check(R"(
+        local x = #({} :: never)
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    CHECK_EQ("never", toString(requireType("x")));
+}
+
+TEST_SUITE_END();
diff --git a/tests/TypePack.test.cpp b/tests/TypePack.test.cpp
index 8a5a65fe..35852c05 100644
--- a/tests/TypePack.test.cpp
+++ b/tests/TypePack.test.cpp
@@ -199,8 +199,6 @@ TEST_CASE_FIXTURE(TypePackFixture, "std_distance")
 
 TEST_CASE("content_reassignment")
 {
-    ScopedFastFlag luauNonCopyableTypeVarFields{"LuauNonCopyableTypeVarFields", true};
-
     TypePackVar myError{Unifiable::Error{}, /*presistent*/ true};
 
     TypeArena arena;
diff --git a/tests/TypeVar.test.cpp b/tests/TypeVar.test.cpp
index 4f8fc502..f4670048 100644
--- a/tests/TypeVar.test.cpp
+++ b/tests/TypeVar.test.cpp
@@ -418,8 +418,6 @@ TEST_CASE("proof_that_isBoolean_uses_all_of")
 
 TEST_CASE("content_reassignment")
 {
-    ScopedFastFlag luauNonCopyableTypeVarFields{"LuauNonCopyableTypeVarFields", true};
-
     TypeVar myAny{AnyTypeVar{}, /*presistent*/ true};
     myAny.normal = true;
     myAny.documentationSymbol = "@global/any";
diff --git a/tests/conformance/vector.lua b/tests/conformance/vector.lua
index 22d6adfc..6164e929 100644
--- a/tests/conformance/vector.lua
+++ b/tests/conformance/vector.lua
@@ -101,4 +101,20 @@ if vector_size == 4 then
 	assert(vector(1, 2, 3, 4).W == 4)
 end
 
+-- negative zero should hash the same as zero
+-- note: our earlier test only really checks the low hash bit, so in absence of perfect avalanche it's insufficient
+do
+	local larget = {}
+	for i = 1, 2^14 do
+	    larget[vector(0, 0, i)] = true
+	end
+
+	larget[vector(0, 0, 0)] = 42
+
+	assert(larget[vector(0, 0, 0)] == 42)
+	assert(larget[vector(0, 0, -0)] == 42)
+	assert(larget[vector(0, -0, 0)] == 42)
+	assert(larget[vector(-0, 0, 0)] == 42)
+end
+
 return 'OK'
diff --git a/tools/natvis/VM.natvis b/tools/natvis/VM.natvis
index ccc7e390..cb2f355f 100644
--- a/tools/natvis/VM.natvis
+++ b/tools/natvis/VM.natvis
@@ -137,16 +137,28 @@
     <DisplayString>{data,s}</DisplayString>
   </Type>
 
+  <Type Name="::CallInfo">
+    <Intrinsic Name="cl" Category="Property" Expression="func->value.gc->cl"/>
+    <Intrinsic Name="isC" Category="Property" Expression="cl().isC"/>
+    <Intrinsic Name="proto" Category="Property" Expression="cl().l.p"/>
+    <Intrinsic Name="pcRel" Category="Property" Expression="savedpc ? savedpc - proto()->code - 1 : 0"/>
+    <Intrinsic Name="line" Category="Property" Expression="proto()->abslineinfo[pcRel() >> proto()->linegaplog2] + proto()->lineinfo[pcRel()]"/>
+
+    <!-- Special frames -->
+    <DisplayString Condition="!func">empty</DisplayString>
+    <DisplayString Condition="func->tt != lua_Type::LUA_TFUNCTION">none</DisplayString>
+
+    <!-- Lua functions-->
+    <DisplayString Condition="!isC() &amp;&amp; proto()->debugname">{proto()->source->data,sb}:{line()} function {proto()->debugname->data,sb}()</DisplayString>
+    <DisplayString Condition="!isC()">{proto()->source->data,sb}:{line()} function()</DisplayString>
+
+    <!-- C functions-->
+    <DisplayString Condition="isC() &amp;&amp; cl().c.debugname">=[C] function {cl().c.debugname,sb}() {cl().c.f,na}</DisplayString>
+    <DisplayString Condition="isC()">=[C] {cl().c.f,na}</DisplayString>
+  </Type>
+
   <Type Name ="::lua_State">
-    <DisplayString Condition="ci-&gt;func-&gt;value.gc-&gt;cl.isC">
-      {ci-&gt;func-&gt;value.gc-&gt;cl.c.f,na}
-    </DisplayString>
-    <DisplayString Condition="!ci-&gt;func-&gt;value.gc-&gt;cl.isC &amp;&amp; ci-&gt;func-&gt;value.gc-&gt;cl.l.p-&gt;debugname" Optional="true">
-      {ci-&gt;func-&gt;value.gc-&gt;cl.l.p-&gt;source-&gt;data,sb}:{ci-&gt;func-&gt;value.gc-&gt;cl.l.p-&gt;linedefined,d} {ci-&gt;func-&gt;value.gc-&gt;cl.l.p-&gt;debugname->data,sb}
-    </DisplayString>
-    <DisplayString Condition="!ci-&gt;func-&gt;value.gc-&gt;cl.isC" Optional="true">
-      {ci-&gt;func-&gt;value.gc-&gt;cl.l.p-&gt;source-&gt;data,sb}:{ci-&gt;func-&gt;value.gc-&gt;cl.l.p-&gt;linedefined,d}
-    </DisplayString>
+    <DisplayString Condition="ci">{ci,na}</DisplayString>
     <DisplayString>thread</DisplayString>
     <Expand>
       <Synthetic Name="[call stack]">
@@ -156,7 +168,7 @@
             <Size>ci-base_ci</Size>
             <!-- the +1 is omitted here to avoid some issues with a blank call -->
             <ValueNode>
-              base_ci[ci-base_ci - $i].func-&gt;value.gc-&gt;cl,view(short)
+              base_ci[ci-base_ci - $i]
             </ValueNode>
           </IndexListItems>
         </Expand>

From 6ad8239e3249d8915e5ad247ad9e429b869f4db4 Mon Sep 17 00:00:00 2001
From: Anaminus <Anaminus@users.noreply.github.com>
Date: Fri, 8 Jul 2022 17:06:25 +0000
Subject: [PATCH 2/4] Improve description of bit32.extract/replace. (#585)

Fix description incorrectly saying that parameter w specifies an upper range. w is actually a width. Proof:

    print(bit32.extract(2^32-1, 3, 4)) -- prints 15, not 1.

Also indicate that the position is 0-based, and that the function will error if the selected range exceeds the allowed bounds.
---
 docs/_pages/library.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/_pages/library.md b/docs/_pages/library.md
index f419d2bf..6ca2c05a 100644
--- a/docs/_pages/library.md
+++ b/docs/_pages/library.md
@@ -683,7 +683,7 @@ Perform a bitwise `and` of all input numbers, and return `true` iff the result i
 function bit32.extract(n: number, f: number, w: number?): number
 ```
 
-Extracts bits at positions `[f..w]` and returns the resulting integer. `w` defaults to `f+1`, so a two-argument version of `extract` returns the bit value at position `f`.
+Extracts bits of `n` at position `f` with a width of `w`, and returns the resulting integer. `w` defaults to `1`, so a two-argument version of `extract` returns the bit value at position `f`. Bits are indexed starting at 0. Errors if `f` and `f+w-1` are not between 0 and 31.
 
 ```
 function bit32.lrotate(n: number, i: number): number
@@ -701,7 +701,7 @@ Shifts `n` to the left by `i` bits (if `i` is negative, a right shift is perform
 function bit32.replace(n: number, r: number, f: number, w: number?): number
 ```
 
-Replaces bits at positions `[f..w]` of number `n` with `r` and returns the resulting integer. `w` defaults to `f+1`, so a three-argument version of `replace` changes one bit at position `f` to `r` (which should be 0 or 1) and returns the result.
+Replaces bits of `n` at position `f` and width `w` with `r`, and returns the resulting integer. `w` defaults to `1`, so a three-argument version of `replace` changes one bit at position `f` to `r` (which should be 0 or 1) and returns the result. Bits are indexed starting at 0. Errors if `f` and `f+w-1` are not between 0 and 31.
 
 ```
 function bit32.rrotate(n: number, i: number): number

From a934f742d81aefa53e8e45fa7eec0042d3fde7fc Mon Sep 17 00:00:00 2001
From: Andy Friesen <afriesen@roblox.com>
Date: Mon, 11 Jul 2022 13:21:23 -0700
Subject: [PATCH 3/4] June recap (#583)

---
 .../_posts/2022-07-07-luau-recap-june-2022.md | 88 +++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 docs/_posts/2022-07-07-luau-recap-june-2022.md

diff --git a/docs/_posts/2022-07-07-luau-recap-june-2022.md b/docs/_posts/2022-07-07-luau-recap-june-2022.md
new file mode 100644
index 00000000..1f58d892
--- /dev/null
+++ b/docs/_posts/2022-07-07-luau-recap-june-2022.md
@@ -0,0 +1,88 @@
+---
+layout: single
+title:  "Luau Recap: June 2022"
+---
+
+Luau is our new language that you can read more about at [https://luau-lang.org](https://luau-lang.org).
+
+[Cross-posted to the [Roblox Developer Forum](https://devforum.roblox.com/t/luau-recap-june-2022/).]
+
+# Lower bounds calculation
+
+A common problem that Luau has is that it primarily works by inspecting expressions in your program and narrowing the _upper bounds_ of the values that can inhabit particular variables.  In other words, each time we see a variable used, we eliminate possible sets of values from that variable's domain.
+
+There are some important cases where this doesn't produce a helpful result.  Take this function for instance:
+
+```lua
+function find_first_if(vec, f)
+	for i, e in ipairs(vec) do
+		if f(e) then
+			return i
+		end
+	end
+
+	return nil
+end
+```
+
+Luau scans the function from top to bottom and first sees the line `return i`.  It draws from this the inference that `find_first_if` must return the type of `i`, namely `number`.
+
+This is fine, but things go sour when we see the line `return nil`.  Since we are always narrowing, we take from this line the judgement that the return type of the function is `nil`.  Since we have already concluded that the function must return `number`, Luau reports an error.
+
+What we actually want to do in this case is to take these `return` statements as inferences about the _lower_ bound of the function's return type.  Instead of saying "this function must return values of type `nil`," we should instead say "this function may _also_ return values of type `nil`."
+
+Lower bounds calculation does precisely this.  Moving forward, Luau will instead infer the type `number?` for the above function.
+
+This does have one unfortunate consequence: If a function has no return type annotation, we will no longer ever report a type error on a `return` statement.  We think this is the right balance but we'll be keeping an eye on things just to be sure.
+
+Lower-bounds calculation is larger and a little bit riskier than other things we've been working on so we've set up a beta feature in Roblox Studio to enable them.  It is called "Experimental Luau language features."
+
+Please try it out and let us know what you think!
+
+## Known bug
+
+We have a known bug with certain kinds of cyclic types when lower-bounds calculation is enabled.  The following, for instance, is known to be problematic.
+
+```lua
+type T = {T?}? -- spuriously reduces to {nil}?
+```
+
+We hope to have this fixed soon.
+
+# All table literals now result in unsealed tables
+
+Previously, the only way to create a sealed table was by with a literal empty table.  We have relaxed this somewhat: Any table created by a `{}` expression is considered to be unsealed within the scope where it was created:
+
+```lua
+local T = {}
+T.x = 5 -- OK
+
+local V = {x=5}
+V.y = 2 -- previously disallowed.  Now OK.
+
+function mkTable()
+    return {x = 5}
+end
+
+local U = mkTable()
+U.y = 2 -- Still disallowed: U is sealed
+```
+
+# Other fixes
+
+* Adjust indentation and whitespace when creating multiline string representations of types, resulting in types that are easier to read.
+* Some small bugfixes to autocomplete
+* Fix a case where accessing a nonexistent property of a table would not result in an error being reported.
+* Improve parser recovery for the incorrect code `function foo() -> ReturnType` (the correct syntax is `function foo(): ReturnType`)
+* Improve the parse error offered for code that improperly uses the `function` keyword to start a type eg `type T = function`
+* Some small crash fixes and performance improvements
+
+# Thanks!
+
+A very special thanks to all of our open source contributors:
+
+* [Allan N Jeremy](https://github.com/AllanJeremy)
+* [Daniel Nachun](https://github.com/danielnachun)
+* [JohnnyMorganz](https://github.com/JohnnyMorganz/)
+* [Petri Häkkinen](https://github.com/petrihakkinen)
+* [Qualadore](https://github.com/Qualadore)

From e87009f5b278dec0213b6f1ed33a422f55e4ef48 Mon Sep 17 00:00:00 2001
From: Alex Orlenko <zxteam@protonmail.com>
Date: Thu, 14 Jul 2022 20:00:37 +0100
Subject: [PATCH 4/4] Add lua_setuserdatatag to update userdata tags (#588)

---
 VM/include/lua.h           | 5 +++--
 VM/src/lapi.cpp            | 8 ++++++++
 tests/Conformance.test.cpp | 4 ++++
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/VM/include/lua.h b/VM/include/lua.h
index 7f9647c8..72edb4a6 100644
--- a/VM/include/lua.h
+++ b/VM/include/lua.h
@@ -64,14 +64,14 @@ enum lua_Type
     LUA_TNIL = 0,     /* must be 0 due to lua_isnoneornil */
     LUA_TBOOLEAN = 1, /* must be 1 due to l_isfalse */
 
-    
+
     LUA_TLIGHTUSERDATA,
     LUA_TNUMBER,
     LUA_TVECTOR,
 
     LUA_TSTRING, /* all types above this must be value types, all types below this must be GC types - see iscollectable */
 
-    
+
     LUA_TTABLE,
     LUA_TFUNCTION,
     LUA_TUSERDATA,
@@ -300,6 +300,7 @@ LUA_API uintptr_t lua_encodepointer(lua_State* L, uintptr_t p);
 
 LUA_API double lua_clock();
 
+LUA_API void lua_setuserdatatag(lua_State* L, int idx, int tag);
 LUA_API void lua_setuserdatadtor(lua_State* L, int tag, void (*dtor)(lua_State*, void*));
 
 LUA_API void lua_clonefunction(lua_State* L, int idx);
diff --git a/VM/src/lapi.cpp b/VM/src/lapi.cpp
index 3c3b7bd0..c2b790ad 100644
--- a/VM/src/lapi.cpp
+++ b/VM/src/lapi.cpp
@@ -1305,6 +1305,14 @@ void lua_unref(lua_State* L, int ref)
     return;
 }
 
+void lua_setuserdatatag(lua_State* L, int idx, int tag)
+{
+    api_check(L, unsigned(tag) < LUA_UTAG_LIMIT);
+    StkId o = index2addr(L, idx);
+    api_check(L, ttisuserdata(o));
+    uvalue(o)->tag = uint8_t(tag);
+}
+
 void lua_setuserdatadtor(lua_State* L, int tag, void (*dtor)(lua_State*, void*))
 {
     api_check(L, unsigned(tag) < LUA_UTAG_LIMIT);
diff --git a/tests/Conformance.test.cpp b/tests/Conformance.test.cpp
index 3f415149..d2311348 100644
--- a/tests/Conformance.test.cpp
+++ b/tests/Conformance.test.cpp
@@ -1152,6 +1152,10 @@ TEST_CASE("UserdataApi")
     CHECK(lua_touserdatatagged(L, -1, 41) == nullptr);
     CHECK(lua_userdatatag(L, -1) == 42);
 
+    lua_setuserdatatag(L, -1, 43);
+    CHECK(lua_userdatatag(L, -1) == 43);
+    lua_setuserdatatag(L, -1, 42);
+
     // user data with inline dtor
     void* ud3 = lua_newuserdatadtor(L, 4, [](void* data) {
         dtorhits += *(int*)data;